diff --git a/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java b/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java index 9864eaa..7d2be69 100644 --- a/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java +++ b/src/main/java/com/gxwebsoft/common/core/security/SecurityConfig.java @@ -79,7 +79,8 @@ public class SecurityConfig { "/api/shop/getShopInfo", "/api/shop/shop-order/test", "/api/qr-code/**", - "/api/shop/order-delivery/notify" + "/api/shop/order-delivery/notify", + "/api/hjc/push/project" ) .permitAll() .anyRequest() diff --git a/src/main/java/com/gxwebsoft/hjc/controller/HjcBidProjectController.java b/src/main/java/com/gxwebsoft/hjc/controller/HjcBidProjectController.java new file mode 100644 index 0000000..6d6fcb3 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/controller/HjcBidProjectController.java @@ -0,0 +1,85 @@ +package com.gxwebsoft.hjc.controller; + +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.hjc.entity.HjcBidProject; +import com.gxwebsoft.hjc.param.HjcBidProjectParam; +import com.gxwebsoft.hjc.service.HjcBidProjectService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +/** + * 汇吉采标书项目(C端浏览 + 管理后台维护) + */ +@Tag(name = "汇吉采-标书项目") +@RestController +@RequestMapping("/api/hjc/bid-project") +public class HjcBidProjectController extends BaseController { + + @Resource + private HjcBidProjectService hjcBidProjectService; + + @Operation(summary = "分页查询(后台)") + @GetMapping("/page") + public ApiResult> page(HjcBidProjectParam param) { + return success(hjcBidProjectService.pageRel(param)); + } + + @Operation(summary = "在售列表(C端,仅上架)") + @GetMapping("/list") + public ApiResult> list(HjcBidProjectParam param) { + param.setStatus(1); + return success(hjcBidProjectService.pageRel(param)); + } + + @Operation(summary = "详情") + @GetMapping("/{id}") + public ApiResult detail(@PathVariable("id") Integer id) { + HjcBidProject project = hjcBidProjectService.getById(id); + if (project == null) { + return fail("标书项目不存在"); + } + return success(project); + } + + @Operation(summary = "新增(后台)") + @PostMapping() + public ApiResult save(@RequestBody HjcBidProject project) { + project.setId(null); + if (project.getTenantId() == null) { + project.setTenantId(getTenantId()); + } + if (project.getStatus() == null) { + project.setStatus(1); + } + if (project.getDataSource() == null) { + project.setDataSource("MANUAL"); + } + if (project.getSaleCount() == null) { + project.setSaleCount(0); + } + hjcBidProjectService.save(project); + return success("保存成功", project.getId()); + } + + @Operation(summary = "更新(后台)") + @PutMapping() + public ApiResult update(@RequestBody HjcBidProject project) { + if (project.getId() == null) { + return fail("ID不能为空"); + } + hjcBidProjectService.updateById(project); + return success("更新成功"); + } + + @Operation(summary = "删除/下架(后台)") + @DeleteMapping("/{id}") + public ApiResult delete(@PathVariable("id") Integer id) { + hjcBidProjectService.removeById(id); + return success("删除成功"); + } +} diff --git a/src/main/java/com/gxwebsoft/hjc/controller/HjcEnterpriseController.java b/src/main/java/com/gxwebsoft/hjc/controller/HjcEnterpriseController.java new file mode 100644 index 0000000..8805d98 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/controller/HjcEnterpriseController.java @@ -0,0 +1,131 @@ +package com.gxwebsoft.hjc.controller; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.hjc.entity.HjcEnterprise; +import com.gxwebsoft.hjc.entity.HjcEnterpriseMaterial; +import com.gxwebsoft.hjc.param.HjcEnterpriseParam; +import com.gxwebsoft.hjc.service.HjcEnterpriseMaterialService; +import com.gxwebsoft.hjc.service.HjcEnterpriseService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 汇吉采企业账号与资质 + */ +@Tag(name = "汇吉采-企业资质") +@RestController +@RequestMapping("/api/hjc/enterprise") +public class HjcEnterpriseController extends BaseController { + + @Resource + private HjcEnterpriseService hjcEnterpriseService; + @Resource + private HjcEnterpriseMaterialService hjcEnterpriseMaterialService; + + @Operation(summary = "当前登录企业的资料") + @GetMapping("/my") + public ApiResult my() { + Integer userId = getLoginUserId(); + if (userId == null) { + return fail("用户未登录"); + } + HjcEnterprise enterprise = hjcEnterpriseService.getByUserId(userId); + if (enterprise != null) { + enterprise.setMaterials(listMaterials(enterprise.getId())); + enterprise.setMobile(getLoginUser().getMobile()); + } + return success(enterprise); + } + + @Operation(summary = "提交/更新企业资质(信息+证件),提交后回到待审核") + @PostMapping("/save") + @Transactional(rollbackFor = Exception.class) + public ApiResult save(@RequestBody HjcEnterprise enterprise) { + Integer userId = getLoginUserId(); + if (userId == null) { + return fail("用户未登录"); + } + HjcEnterprise exist = hjcEnterpriseService.getByUserId(userId); + boolean isNew = exist == null; + if (isNew) { + enterprise.setId(null); + enterprise.setUserId(userId); + enterprise.setAuthStatus(0); + if (enterprise.getTenantId() == null) { + enterprise.setTenantId(getTenantId()); + } + hjcEnterpriseService.save(enterprise); + } else { + enterprise.setId(exist.getId()); + enterprise.setUserId(userId); + enterprise.setAuthStatus(0); + hjcEnterpriseService.updateById(enterprise); + } + Integer enterpriseId = isNew ? enterprise.getId() : exist.getId(); + + // 替换证件材料:先删旧再插新 + hjcEnterpriseMaterialService.remove(new LambdaQueryWrapper() + .eq(HjcEnterpriseMaterial::getEnterpriseId, enterpriseId)); + List materials = enterprise.getMaterials(); + if (materials != null) { + for (HjcEnterpriseMaterial m : materials) { + if (StrUtil.isBlank(m.getFileUrl())) { + continue; + } + m.setId(null); + m.setEnterpriseId(enterpriseId); + if (m.getTenantId() == null) { + m.setTenantId(getTenantId()); + } + hjcEnterpriseMaterialService.save(m); + } + } + return success("提交成功,等待审核", enterpriseId); + } + + @Operation(summary = "后台-企业资质分页") + @GetMapping("/page") + public ApiResult> page(HjcEnterpriseParam param) { + return success(hjcEnterpriseService.pageRel(param)); + } + + @Operation(summary = "后台-资质详情") + @GetMapping("/{id}") + public ApiResult detail(@PathVariable("id") Integer id) { + HjcEnterprise enterprise = hjcEnterpriseService.getById(id); + if (enterprise == null) { + return fail("企业不存在"); + } + enterprise.setMaterials(listMaterials(id)); + return success(enterprise); + } + + @Operation(summary = "后台-审核:通过/驳回") + @PutMapping("/auth") + public ApiResult audit(@RequestBody HjcEnterprise param) { + if (param.getId() == null || param.getAuthStatus() == null) { + return fail("审核参数不完整"); + } + HjcEnterprise enterprise = new HjcEnterprise(); + enterprise.setId(param.getId()); + enterprise.setAuthStatus(param.getAuthStatus()); + enterprise.setRejectReason(param.getRejectReason()); + hjcEnterpriseService.updateById(enterprise); + return success("审核完成"); + } + + private List listMaterials(Integer enterpriseId) { + return hjcEnterpriseMaterialService.list(new LambdaQueryWrapper() + .eq(HjcEnterpriseMaterial::getEnterpriseId, enterpriseId) + .orderByAsc(HjcEnterpriseMaterial::getId)); + } +} diff --git a/src/main/java/com/gxwebsoft/hjc/controller/HjcOrderController.java b/src/main/java/com/gxwebsoft/hjc/controller/HjcOrderController.java new file mode 100644 index 0000000..49e3ca2 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/controller/HjcOrderController.java @@ -0,0 +1,139 @@ +package com.gxwebsoft.hjc.controller; + +import cn.hutool.core.util.RandomUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.hjc.dto.CreateOrderRequest; +import com.gxwebsoft.hjc.entity.HjcBidProject; +import com.gxwebsoft.hjc.entity.HjcEnterprise; +import com.gxwebsoft.hjc.entity.HjcOrder; +import com.gxwebsoft.hjc.param.HjcOrderParam; +import com.gxwebsoft.hjc.service.HjcBidProjectService; +import com.gxwebsoft.hjc.service.HjcEnterpriseService; +import com.gxwebsoft.hjc.service.HjcOrderService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +/** + * 汇吉采标书订单(下单 + 我的订单 + 后台订单) + */ +@Tag(name = "汇吉采-标书订单") +@RestController +@RequestMapping("/api/hjc/order") +public class HjcOrderController extends BaseController { + + private static final DateTimeFormatter ORDER_NO_FMT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); + + @Resource + private HjcOrderService hjcOrderService; + @Resource + private HjcBidProjectService hjcBidProjectService; + @Resource + private HjcEnterpriseService hjcEnterpriseService; + + @Operation(summary = "下单(创建待支付订单)") + @PostMapping("/create") + public ApiResult create(@RequestBody CreateOrderRequest request) { + Integer userId = getLoginUserId(); + if (userId == null) { + return fail("用户未登录"); + } + HjcEnterprise enterprise = hjcEnterpriseService.getByUserId(userId); + if (enterprise == null) { + return fail("请先完善企业信息"); + } + if (enterprise.getAuthStatus() == null || enterprise.getAuthStatus() != 1) { + return fail("企业资质未通过审核,暂无权限购买"); + } + if (request.getProjectId() == null) { + return fail("标书项目ID不能为空"); + } + HjcBidProject project = hjcBidProjectService.getById(request.getProjectId()); + if (project == null) { + return fail("标书项目不存在"); + } + if (project.getStatus() == null || project.getStatus() != 1) { + return fail("该项目未在售"); + } + int quantity = request.getQuantity() == null || request.getQuantity() < 1 ? 1 : request.getQuantity(); + BigDecimal unitPrice = project.getTenderPrice() == null ? BigDecimal.ZERO : project.getTenderPrice(); + + String orderNo = "HJC" + ORDER_NO_FMT.format(LocalDateTime.now()) + RandomUtil.randomNumbers(4); + + HjcOrder order = new HjcOrder(); + order.setOrderNo(orderNo); + order.setProjectId(project.getId()); + order.setProjectNo(project.getProjectNo()); + order.setProjectName(project.getProjectName()); + order.setEnterpriseId(enterprise.getId()); + order.setEnterpriseName(enterprise.getName()); + order.setContactName(firstNotBlank(request.getContactName(), enterprise.getAgentName())); + order.setContactPhone(firstNotBlank(request.getContactPhone(), enterprise.getAgentPhone())); + order.setContactEmail(firstNotBlank(request.getContactEmail(), enterprise.getAgentEmail())); + order.setQuantity(quantity); + order.setUnitPrice(unitPrice); + order.setTotalAmount(unitPrice.multiply(BigDecimal.valueOf(quantity))); + order.setPayMethod("WECHAT_NATIVE"); + order.setPayStatus(0); + order.setOrderStatus(0); + order.setInvoiceStatus(0); + order.setTenantId(enterprise.getTenantId()); + order.setDeleted(0); + hjcOrderService.save(order); + + // 购买数量累加 + HjcBidProject up = new HjcBidProject(); + up.setId(project.getId()); + up.setSaleCount((project.getSaleCount() == null ? 0 : project.getSaleCount()) + quantity); + hjcBidProjectService.updateById(up); + + return success("下单成功", order); + } + + @Operation(summary = "我的订单") + @GetMapping("/my") + public ApiResult my() { + Integer userId = getLoginUserId(); + if (userId == null) { + return fail("用户未登录"); + } + HjcEnterprise enterprise = hjcEnterpriseService.getByUserId(userId); + if (enterprise == null) { + return fail("企业不存在"); + } + List list = hjcOrderService.list(new LambdaQueryWrapper() + .eq(HjcOrder::getEnterpriseId, enterprise.getId()) + .orderByDesc(HjcOrder::getId)); + return success(list); + } + + @Operation(summary = "订单详情") + @GetMapping("/{id}") + public ApiResult detail(@PathVariable("id") Integer id) { + HjcOrder order = hjcOrderService.getById(id); + if (order == null) { + return fail("订单不存在"); + } + order.setProject(hjcBidProjectService.getById(order.getProjectId())); + return success(order); + } + + @Operation(summary = "后台-订单分页") + @GetMapping("/page") + public ApiResult> page(HjcOrderParam param) { + return success(hjcOrderService.pageRel(param)); + } + + private String firstNotBlank(String a, String b) { + return a != null && !a.trim().isEmpty() ? a : b; + } +} diff --git a/src/main/java/com/gxwebsoft/hjc/controller/HjcPushController.java b/src/main/java/com/gxwebsoft/hjc/controller/HjcPushController.java new file mode 100644 index 0000000..9b5095f --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/controller/HjcPushController.java @@ -0,0 +1,61 @@ +package com.gxwebsoft.hjc.controller; + +import com.gxwebsoft.common.core.web.ApiResult; +import com.gxwebsoft.common.core.web.BaseController; +import com.gxwebsoft.hjc.dto.HjcOneStopProjectPush; +import com.gxwebsoft.hjc.entity.HjcOrder; +import com.gxwebsoft.hjc.service.HjcBizService; +import com.gxwebsoft.hjc.service.HjcOrderService; +import com.gxwebsoft.hjc.util.HjcOneStopAuthUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +/** + * 汇吉采一站式平台双向对接 + * + * 入向:POST /api/hjc/push/project —— 一站式推送标书/中标公告,对称鉴权 + * 出向:手动/定时触发 createPurchaseDetails 推送订单 + */ +@Tag(name = "汇吉采-一站式对接") +@RestController +@RequestMapping("/api/hjc/push") +public class HjcPushController extends BaseController { + + @Resource + private HjcBizService hjcBizService; + @Resource + private HjcOrderService hjcOrderService; + + @Operation(summary = "入向:接收一站式推送的标书/中标公告") + @PostMapping("/project") + public ApiResult receiveProject(@RequestHeader(value = "appKey", required = false) String appKey, + @RequestHeader(value = "timestamp", required = false) String timestamp, + @RequestHeader(value = "sign", required = false) String sign, + @RequestBody HjcOneStopProjectPush push) { + if (!HjcOneStopAuthUtil.verify(appKey, timestamp, sign)) { + return fail("鉴权失败"); + } + if (push == null || push.getProjectNo() == null) { + return fail("项目编号不能为空"); + } + Integer tenantId = getTenantId(); + if (tenantId == null) { + return fail("租户ID不能为空"); + } + return success("接收成功", hjcBizService.upsertFromPush(push, tenantId)); + } + + @Operation(summary = "出向:手动触发订单推送(createPurchaseDetails)") + @PostMapping("/order/{orderNo}") + public ApiResult triggerPush(@PathVariable("orderNo") String orderNo) { + HjcOrder order = hjcOrderService.getByOrderNo(orderNo); + if (order == null) { + return fail("订单不存在"); + } + hjcBizService.pushOrderToOneStop(order); + return success("已触发推送"); + } +} diff --git a/src/main/java/com/gxwebsoft/hjc/dto/CreateOrderRequest.java b/src/main/java/com/gxwebsoft/hjc/dto/CreateOrderRequest.java new file mode 100644 index 0000000..f20a6ca --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/dto/CreateOrderRequest.java @@ -0,0 +1,27 @@ +package com.gxwebsoft.hjc.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 汇吉采下单请求 + */ +@Data +@Schema(name = "CreateOrderRequest", description = "汇吉采下单请求") +public class CreateOrderRequest { + + @Schema(description = "标书项目ID", required = true) + private Integer projectId; + + @Schema(description = "购买数量", required = true) + private Integer quantity = 1; + + @Schema(description = "购买联系人") + private String contactName; + + @Schema(description = "购买联系电话") + private String contactPhone; + + @Schema(description = "购买联系邮箱") + private String contactEmail; +} diff --git a/src/main/java/com/gxwebsoft/hjc/dto/CreatePurchaseDetails.java b/src/main/java/com/gxwebsoft/hjc/dto/CreatePurchaseDetails.java new file mode 100644 index 0000000..6e18c0c --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/dto/CreatePurchaseDetails.java @@ -0,0 +1,65 @@ +package com.gxwebsoft.hjc.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 汇吉采 → 一站式平台:POST /api/biz/createPurchaseDetails 请求体(Q9 字段表)。 + */ +@Data +@Schema(name = "CreatePurchaseDetails", description = "标书购买记录/订单推送体") +public class CreatePurchaseDetails { + + @Schema(description = "幂等键") + private String idempotencyKey; + + @Schema(description = "订单号") + private String orderNo; + + @Schema(description = "项目编号") + private String projectNo; + + @Schema(description = "项目名称") + private String projectName; + + @Schema(description = "标书单价(信息服务费)") + private BigDecimal tenderPrice; + + @Schema(description = "购买数量") + private Integer quantity; + + @Schema(description = "订单总额") + private BigDecimal totalAmount; + + @Schema(description = "购买企业") + private Buyer buyer; + + @Schema(description = "支付时间,yyyy-MM-dd HH:mm:ss") + private String paidAt; + + @Schema(description = "支付方式:WECHAT_MP/ALIPAY") + private String payMethod; + + @Schema(description = "状态:PAID/REFUNDED") + private String status; + + @Schema(description = "开票状态:NONE/APPLIED/ISSUED") + private String invoiceStatus; + + @Data + @Schema(name = "CreatePurchaseDetails.Buyer", description = "购买企业信息") + public static class Buyer { + @Schema(description = "企业名称") + private String enterpriseName; + @Schema(description = "统一社会信用代码") + private String creditCode; + @Schema(description = "经办人姓名") + private String contactName; + @Schema(description = "经办人手机号") + private String contactPhone; + @Schema(description = "经办人邮箱") + private String contactEmail; + } +} diff --git a/src/main/java/com/gxwebsoft/hjc/dto/HjcOneStopProjectPush.java b/src/main/java/com/gxwebsoft/hjc/dto/HjcOneStopProjectPush.java new file mode 100644 index 0000000..291c937 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/dto/HjcOneStopProjectPush.java @@ -0,0 +1,58 @@ +package com.gxwebsoft.hjc.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 一站式平台 → 汇吉采:中标公告/标书推送报文。 + * 对应需求字段:projectNo/projectName/tenderPrice/files/tenderOnsaleTime/tenderOffsaleTime/ + * bulletinName/customerName/supplierName/bidAmount/content/fileList/needSellTender/sellingMethod + */ +@Data +@Schema(name = "HjcOneStopProjectPush", description = "一站式标书/中标公告推送报文") +public class HjcOneStopProjectPush { + + @Schema(description = "是否卖标书,needSellTender") + private Integer needSellTender; + + @Schema(description = "售卖方式:1公司财务 2公众号 3交易中心 4政采云") + private Integer sellingMethod; + + @Schema(description = "项目编号") + private String projectNo; + + @Schema(description = "项目名称") + private String projectName; + + @Schema(description = "标书价格") + private BigDecimal tenderPrice; + + @Schema(description = "标书附件(数组JSON或逗号分隔)") + private String files; + + @Schema(description = "开售时间,yyyy-MM-dd HH:mm:ss") + private String tenderOnsaleTime; + + @Schema(description = "截止时间/停售时间,yyyy-MM-dd HH:mm:ss") + private String tenderOffsaleTime; + + @Schema(description = "公告标题") + private String bulletinName; + + @Schema(description = "招标人") + private String customerName; + + @Schema(description = "中标公司") + private String supplierName; + + @Schema(description = "中标金额") + private BigDecimal bidAmount; + + @Schema(description = "公告正文") + private String content; + + @Schema(description = "公告附件(数组JSON或逗号分隔)") + private String fileList; +} diff --git a/src/main/java/com/gxwebsoft/hjc/entity/HjcBidProject.java b/src/main/java/com/gxwebsoft/hjc/entity/HjcBidProject.java new file mode 100644 index 0000000..476944d --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/entity/HjcBidProject.java @@ -0,0 +1,108 @@ +package com.gxwebsoft.hjc.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 汇吉采标书项目(项目即标书,单表;甲方确认一个项目一本标书) + * + * @author WebSoft + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "HjcBidProject对象", description = "汇吉采标书项目(项目即标书)") +public class HjcBidProject implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "项目编号(upsert键,一站式推送用)") + private String projectNo; + + @Schema(description = "项目名称") + private String projectName; + + @Schema(description = "项目分类:服务类/工程类/货物类") + private String category; + + @Schema(description = "发布时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime publishTime; + + @Schema(description = "投标截止时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime deadlineTime; + + @Schema(description = "招标人(customerName)") + private String tenderer; + + @Schema(description = "中标公司(supplierName)") + private String winnerSupplier; + + @Schema(description = "中标金额(bidAmount)") + private BigDecimal bidAmount; + + @Schema(description = "公告标题(bulletinName)") + private String bulletinTitle; + + @Schema(description = "公告正文(content)") + private String bulletinContent; + + @Schema(description = "公告附件(fileList, JSON数组字符串)") + private String bulletinFileList; + + @Schema(description = "标书价格/信息服务费(tenderPrice)") + private BigDecimal tenderPrice; + + @Schema(description = "标书附件(files, JSON数组字符串)") + private String tenderFile; + + @Schema(description = "开售时间(tenderOnsaleTime)") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime onsaleTime; + + @Schema(description = "停售时间(tenderOffsaleTime)") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime offsaleTime; + + @Schema(description = "售卖方式:1公司财务 2公众号 3交易中心 4政采云") + private Integer sellingMethod; + + @Schema(description = "是否卖标书(needSellTender):0否 1是") + private Integer needSell; + + @Schema(description = "状态:1上架(onsale) 0下架/停售(ended)") + private Integer status; + + @Schema(description = "来源:PUSH一站式推送 / MANUAL后台手工") + private String dataSource; + + @Schema(description = "已售数量") + private Integer saleCount; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; +} diff --git a/src/main/java/com/gxwebsoft/hjc/entity/HjcEnterprise.java b/src/main/java/com/gxwebsoft/hjc/entity/HjcEnterprise.java new file mode 100644 index 0000000..165135e --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/entity/HjcEnterprise.java @@ -0,0 +1,90 @@ +package com.gxwebsoft.hjc.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 汇吉采企业账号与资质(关联 common.system.User) + * + * @author WebSoft + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "HjcEnterprise对象", description = "汇吉采企业账号与资质") +public class HjcEnterprise implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "关联登录用户ID(common user)") + private Integer userId; + + @Schema(description = "企业名称") + private String name; + + @Schema(description = "纳税人识别号/统一社会信用代码") + private String creditCode; + + @Schema(description = "企业联系电话") + private String contactPhone; + + @Schema(description = "企业邮箱") + private String contactEmail; + + @Schema(description = "企业地址") + private String address; + + @Schema(description = "经办人姓名") + private String agentName; + + @Schema(description = "经办人邮箱") + private String agentEmail; + + @Schema(description = "经办人手机号") + private String agentPhone; + + @Schema(description = "授权委托书到期时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime authorizeExpire; + + @Schema(description = "资质状态:0待审核 1已通过 2已驳回") + private Integer authStatus; + + @Schema(description = "驳回原因") + private String rejectReason; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "资质证件材料") + @TableField(exist = false) + private List materials; + + @Schema(description = "登录用户手机号(脱敏, 非DB)") + @TableField(exist = false) + private String mobile; +} diff --git a/src/main/java/com/gxwebsoft/hjc/entity/HjcEnterpriseMaterial.java b/src/main/java/com/gxwebsoft/hjc/entity/HjcEnterpriseMaterial.java new file mode 100644 index 0000000..f02e157 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/entity/HjcEnterpriseMaterial.java @@ -0,0 +1,55 @@ +package com.gxwebsoft.hjc.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 汇吉采企业资质证件材料 + * + * @author WebSoft + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "HjcEnterpriseMaterial对象", description = "汇吉采企业资质证件材料") +public class HjcEnterpriseMaterial implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "企业ID") + private Integer enterpriseId; + + @Schema(description = "材料类型:idcard_front/idcard_back/handbook/license") + private String materialType; + + @Schema(description = "材料名称") + private String materialName; + + @Schema(description = "文件地址") + private String fileUrl; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; +} diff --git a/src/main/java/com/gxwebsoft/hjc/entity/HjcOrder.java b/src/main/java/com/gxwebsoft/hjc/entity/HjcOrder.java new file mode 100644 index 0000000..027be86 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/entity/HjcOrder.java @@ -0,0 +1,101 @@ +package com.gxwebsoft.hjc.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 汇吉采标书订单 + * + * @author WebSoft + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "HjcOrder对象", description = "汇吉采标书订单") +public class HjcOrder implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "订单号") + private String orderNo; + + @Schema(description = "标书项目ID") + private Integer projectId; + + @Schema(description = "项目编号(冗余)") + private String projectNo; + + @Schema(description = "项目名称(冗余)") + private String projectName; + + @Schema(description = "购买企业ID") + private Integer enterpriseId; + + @Schema(description = "购买企业名称(冗余)") + private String enterpriseName; + + @Schema(description = "购买联系人") + private String contactName; + + @Schema(description = "购买联系电话") + private String contactPhone; + + @Schema(description = "购买联系邮箱") + private String contactEmail; + + @Schema(description = "购买数量") + private Integer quantity; + + @Schema(description = "单价(信息服务费)") + private BigDecimal unitPrice; + + @Schema(description = "订单总额") + private BigDecimal totalAmount; + + @Schema(description = "支付方式:WECHAT_NATIVE/ALIPAY") + private String payMethod; + + @Schema(description = "支付时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime payTime; + + @Schema(description = "支付状态:0待支付 1支付成功 2支付失败 3已退款") + private Integer payStatus; + + @Schema(description = "订单状态:0待支付 1已完成 2已取消") + private Integer orderStatus; + + @Schema(description = "开票状态:0未开票 1已申请 2已开票") + private Integer invoiceStatus; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "标书项目") + @TableField(exist = false) + private HjcBidProject project; +} diff --git a/src/main/java/com/gxwebsoft/hjc/entity/HjcOrderPushLog.java b/src/main/java/com/gxwebsoft/hjc/entity/HjcOrderPushLog.java new file mode 100644 index 0000000..2679a8a --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/entity/HjcOrderPushLog.java @@ -0,0 +1,71 @@ +package com.gxwebsoft.hjc.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serializable; +import java.time.LocalDateTime; + +/** + * 汇吉采一站式订单推送日志(幂等+重试) + * + * @author WebSoft + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Schema(name = "HjcOrderPushLog对象", description = "汇吉采一站式订单推送日志") +public class HjcOrderPushLog implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "ID") + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + + @Schema(description = "订单ID") + private Integer orderId; + + @Schema(description = "订单号(一站式幂等键)") + private String orderNo; + + @Schema(description = "推送请求体(JSON)") + private String payload; + + @Schema(description = "推送状态:0待推送 1成功 2失败") + private Integer pushStatus; + + @Schema(description = "一站式HTTP状态码") + private Integer httpCode; + + @Schema(description = "一站式返回内容") + private String responseBody; + + @Schema(description = "失败原因") + private String errorMsg; + + @Schema(description = "已尝试次数") + private Integer attemptCount; + + @Schema(description = "下次重试时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime nextRetryTime; + + @Schema(description = "租户ID") + private Integer tenantId; + + @Schema(description = "是否删除, 0否, 1是") + @TableLogic + private Integer deleted; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; +} diff --git a/src/main/java/com/gxwebsoft/hjc/mapper/HjcBidProjectMapper.java b/src/main/java/com/gxwebsoft/hjc/mapper/HjcBidProjectMapper.java new file mode 100644 index 0000000..126cee9 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/mapper/HjcBidProjectMapper.java @@ -0,0 +1,23 @@ +package com.gxwebsoft.hjc.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.gxwebsoft.hjc.entity.HjcBidProject; +import com.gxwebsoft.hjc.param.HjcBidProjectParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface HjcBidProjectMapper extends BaseMapper { + + List selectPageRel(@Param("page") IPage page, @Param("param") HjcBidProjectParam param); + + List selectListRel(@Param("param") HjcBidProjectParam param); + + /** + * 按项目编号取标书项目(忽略租户隔离,用于一站式推送 upsert) + */ + @InterceptorIgnore(tenantLine = "true") + HjcBidProject getByProjectNo(@Param("projectNo") String projectNo); +} diff --git a/src/main/java/com/gxwebsoft/hjc/mapper/HjcEnterpriseMapper.java b/src/main/java/com/gxwebsoft/hjc/mapper/HjcEnterpriseMapper.java new file mode 100644 index 0000000..d4ab75f --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/mapper/HjcEnterpriseMapper.java @@ -0,0 +1,23 @@ +package com.gxwebsoft.hjc.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.gxwebsoft.hjc.entity.HjcEnterprise; +import com.gxwebsoft.hjc.param.HjcEnterpriseParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface HjcEnterpriseMapper extends BaseMapper { + + List selectPageRel(@Param("page") IPage page, @Param("param") HjcEnterpriseParam param); + + List selectListRel(@Param("param") HjcEnterpriseParam param); + + /** + * 按登录用户ID取企业(忽略租户隔离,用于登录后取企业资料) + */ + @InterceptorIgnore(tenantLine = "true") + HjcEnterprise getByUserId(@Param("userId") Integer userId); +} diff --git a/src/main/java/com/gxwebsoft/hjc/mapper/HjcEnterpriseMaterialMapper.java b/src/main/java/com/gxwebsoft/hjc/mapper/HjcEnterpriseMaterialMapper.java new file mode 100644 index 0000000..772b12a --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/mapper/HjcEnterpriseMaterialMapper.java @@ -0,0 +1,16 @@ +package com.gxwebsoft.hjc.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.hjc.entity.HjcEnterpriseMaterial; +import com.gxwebsoft.hjc.param.HjcEnterpriseMaterialParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface HjcEnterpriseMaterialMapper extends BaseMapper { + + List selectPageRel(@Param("page") IPage page, @Param("param") HjcEnterpriseMaterialParam param); + + List selectListRel(@Param("param") HjcEnterpriseMaterialParam param); +} diff --git a/src/main/java/com/gxwebsoft/hjc/mapper/HjcOrderMapper.java b/src/main/java/com/gxwebsoft/hjc/mapper/HjcOrderMapper.java new file mode 100644 index 0000000..669e66e --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/mapper/HjcOrderMapper.java @@ -0,0 +1,23 @@ +package com.gxwebsoft.hjc.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; +import com.gxwebsoft.hjc.entity.HjcOrder; +import com.gxwebsoft.hjc.param.HjcOrderParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface HjcOrderMapper extends BaseMapper { + + List selectPageRel(@Param("page") IPage page, @Param("param") HjcOrderParam param); + + List selectListRel(@Param("param") HjcOrderParam param); + + /** + * 按订单号取订单(忽略租户隔离,用于支付回调) + */ + @InterceptorIgnore(tenantLine = "true") + HjcOrder getByOrderNo(@Param("orderNo") String orderNo); +} diff --git a/src/main/java/com/gxwebsoft/hjc/mapper/HjcOrderPushLogMapper.java b/src/main/java/com/gxwebsoft/hjc/mapper/HjcOrderPushLogMapper.java new file mode 100644 index 0000000..c91932a --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/mapper/HjcOrderPushLogMapper.java @@ -0,0 +1,16 @@ +package com.gxwebsoft.hjc.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.gxwebsoft.hjc.entity.HjcOrderPushLog; +import com.gxwebsoft.hjc.param.HjcOrderPushLogParam; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface HjcOrderPushLogMapper extends BaseMapper { + + List selectPageRel(@Param("page") IPage page, @Param("param") HjcOrderPushLogParam param); + + List selectListRel(@Param("param") HjcOrderPushLogParam param); +} diff --git a/src/main/java/com/gxwebsoft/hjc/mapper/xml/HjcBidProjectMapper.xml b/src/main/java/com/gxwebsoft/hjc/mapper/xml/HjcBidProjectMapper.xml new file mode 100644 index 0000000..233e903 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/mapper/xml/HjcBidProjectMapper.xml @@ -0,0 +1,61 @@ + + + + + + + SELECT a.* + FROM hjc_bid_project a + + + AND a.id = #{param.id} + + + AND a.project_no = #{param.projectNo} + + + AND a.project_name LIKE CONCAT('%', #{param.projectName}, '%') + + + AND a.category = #{param.category} + + + AND a.status = #{param.status} + + + AND a.selling_method = #{param.sellingMethod} + + + AND a.need_sell = #{param.needSell} + + + AND a.data_source = #{param.dataSource} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.project_name LIKE CONCAT('%', #{param.keywords}, '%') + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/hjc/mapper/xml/HjcEnterpriseMapper.xml b/src/main/java/com/gxwebsoft/hjc/mapper/xml/HjcEnterpriseMapper.xml new file mode 100644 index 0000000..8b7fa3d --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/mapper/xml/HjcEnterpriseMapper.xml @@ -0,0 +1,52 @@ + + + + + + + SELECT a.* + FROM hjc_enterprise a + + + AND a.id = #{param.id} + + + AND a.user_id = #{param.userId} + + + AND a.name LIKE CONCAT('%', #{param.name}, '%') + + + AND a.credit_code = #{param.creditCode} + + + AND a.auth_status = #{param.authStatus} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.name LIKE CONCAT('%', #{param.keywords}, '%') + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/hjc/mapper/xml/HjcEnterpriseMaterialMapper.xml b/src/main/java/com/gxwebsoft/hjc/mapper/xml/HjcEnterpriseMaterialMapper.xml new file mode 100644 index 0000000..1f2685f --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/mapper/xml/HjcEnterpriseMaterialMapper.xml @@ -0,0 +1,36 @@ + + + + + + + SELECT a.* + FROM hjc_enterprise_material a + + + AND a.id = #{param.id} + + + AND a.enterprise_id = #{param.enterpriseId} + + + AND a.material_type = #{param.materialType} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/hjc/mapper/xml/HjcOrderMapper.xml b/src/main/java/com/gxwebsoft/hjc/mapper/xml/HjcOrderMapper.xml new file mode 100644 index 0000000..f46b86b --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/mapper/xml/HjcOrderMapper.xml @@ -0,0 +1,64 @@ + + + + + + + SELECT a.* + FROM hjc_order a + + + AND a.id = #{param.id} + + + AND a.order_no = #{param.orderNo} + + + AND a.project_id = #{param.projectId} + + + AND a.project_no = #{param.projectNo} + + + AND a.enterprise_id = #{param.enterpriseId} + + + AND a.project_name LIKE CONCAT('%', #{param.projectName}, '%') + + + AND a.pay_status = #{param.payStatus} + + + AND a.order_status = #{param.orderStatus} + + + AND a.pay_method = #{param.payMethod} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + AND a.project_name LIKE CONCAT('%', #{param.keywords}, '%') + + + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/hjc/mapper/xml/HjcOrderPushLogMapper.xml b/src/main/java/com/gxwebsoft/hjc/mapper/xml/HjcOrderPushLogMapper.xml new file mode 100644 index 0000000..e1823a6 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/mapper/xml/HjcOrderPushLogMapper.xml @@ -0,0 +1,39 @@ + + + + + + + SELECT a.* + FROM hjc_order_push_log a + + + AND a.id = #{param.id} + + + AND a.order_id = #{param.orderId} + + + AND a.order_no = #{param.orderNo} + + + AND a.push_status = #{param.pushStatus} + + + AND a.create_time >= #{param.createTimeStart} + + + AND a.create_time <= #{param.createTimeEnd} + + + + + + + + + diff --git a/src/main/java/com/gxwebsoft/hjc/param/HjcBidProjectParam.java b/src/main/java/com/gxwebsoft/hjc/param/HjcBidProjectParam.java new file mode 100644 index 0000000..39f2ec5 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/param/HjcBidProjectParam.java @@ -0,0 +1,45 @@ +package com.gxwebsoft.hjc.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 汇吉采标书项目查询参数 + * + * @author WebSoft + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "HjcBidProjectParam对象", description = "汇吉采标书项目查询参数") +public class HjcBidProjectParam extends BaseParam { + + @QueryField(type = QueryType.EQ) + private Integer id; + + @QueryField(type = QueryType.EQ) + private String projectNo; + + @QueryField(type = QueryType.LIKE) + private String projectName; + + @QueryField(type = QueryType.EQ) + private String category; + + @QueryField(type = QueryType.EQ) + private Integer status; + + @QueryField(type = QueryType.EQ) + private Integer sellingMethod; + + @QueryField(type = QueryType.EQ) + private Integer needSell; + + @QueryField(type = QueryType.EQ) + private String dataSource; +} diff --git a/src/main/java/com/gxwebsoft/hjc/param/HjcEnterpriseMaterialParam.java b/src/main/java/com/gxwebsoft/hjc/param/HjcEnterpriseMaterialParam.java new file mode 100644 index 0000000..850f519 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/param/HjcEnterpriseMaterialParam.java @@ -0,0 +1,30 @@ +package com.gxwebsoft.hjc.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 汇吉采企业资质证件材料查询参数 + * + * @author WebSoft + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "HjcEnterpriseMaterialParam对象", description = "汇吉采企业资质证件材料查询参数") +public class HjcEnterpriseMaterialParam extends BaseParam { + + @QueryField(type = QueryType.EQ) + private Integer id; + + @QueryField(type = QueryType.EQ) + private Integer enterpriseId; + + @QueryField(type = QueryType.EQ) + private String materialType; +} diff --git a/src/main/java/com/gxwebsoft/hjc/param/HjcEnterpriseParam.java b/src/main/java/com/gxwebsoft/hjc/param/HjcEnterpriseParam.java new file mode 100644 index 0000000..e5648ce --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/param/HjcEnterpriseParam.java @@ -0,0 +1,36 @@ +package com.gxwebsoft.hjc.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 汇吉采企业账号与资质查询参数 + * + * @author WebSoft + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "HjcEnterpriseParam对象", description = "汇吉采企业账号与资质查询参数") +public class HjcEnterpriseParam extends BaseParam { + + @QueryField(type = QueryType.EQ) + private Integer id; + + @QueryField(type = QueryType.EQ) + private Integer userId; + + @QueryField(type = QueryType.LIKE) + private String name; + + @QueryField(type = QueryType.EQ) + private String creditCode; + + @QueryField(type = QueryType.EQ) + private Integer authStatus; +} diff --git a/src/main/java/com/gxwebsoft/hjc/param/HjcOrderParam.java b/src/main/java/com/gxwebsoft/hjc/param/HjcOrderParam.java new file mode 100644 index 0000000..7bd8a73 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/param/HjcOrderParam.java @@ -0,0 +1,48 @@ +package com.gxwebsoft.hjc.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 汇吉采标书订单查询参数 + * + * @author WebSoft + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "HjcOrderParam对象", description = "汇吉采标书订单查询参数") +public class HjcOrderParam extends BaseParam { + + @QueryField(type = QueryType.EQ) + private Integer id; + + @QueryField(type = QueryType.EQ) + private String orderNo; + + @QueryField(type = QueryType.EQ) + private Integer projectId; + + @QueryField(type = QueryType.EQ) + private String projectNo; + + @QueryField(type = QueryType.EQ) + private Integer enterpriseId; + + @QueryField(type = QueryType.LIKE) + private String projectName; + + @QueryField(type = QueryType.EQ) + private Integer payStatus; + + @QueryField(type = QueryType.EQ) + private Integer orderStatus; + + @QueryField(type = QueryType.EQ) + private String payMethod; +} diff --git a/src/main/java/com/gxwebsoft/hjc/param/HjcOrderPushLogParam.java b/src/main/java/com/gxwebsoft/hjc/param/HjcOrderPushLogParam.java new file mode 100644 index 0000000..8182e41 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/param/HjcOrderPushLogParam.java @@ -0,0 +1,33 @@ +package com.gxwebsoft.hjc.param; + +import com.gxwebsoft.common.core.annotation.QueryField; +import com.gxwebsoft.common.core.annotation.QueryType; +import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 汇吉采一站式订单推送日志查询参数 + * + * @author WebSoft + */ +@Data +@EqualsAndHashCode(callSuper = false) +@JsonInclude(JsonInclude.Include.NON_NULL) +@Schema(name = "HjcOrderPushLogParam对象", description = "汇吉采一站式订单推送日志查询参数") +public class HjcOrderPushLogParam extends BaseParam { + + @QueryField(type = QueryType.EQ) + private Integer id; + + @QueryField(type = QueryType.EQ) + private Integer orderId; + + @QueryField(type = QueryType.EQ) + private String orderNo; + + @QueryField(type = QueryType.EQ) + private Integer pushStatus; +} diff --git a/src/main/java/com/gxwebsoft/hjc/service/HjcBidProjectService.java b/src/main/java/com/gxwebsoft/hjc/service/HjcBidProjectService.java new file mode 100644 index 0000000..c1329b1 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/service/HjcBidProjectService.java @@ -0,0 +1,17 @@ +package com.gxwebsoft.hjc.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.hjc.entity.HjcBidProject; +import com.gxwebsoft.hjc.param.HjcBidProjectParam; + +import java.util.List; + +public interface HjcBidProjectService extends IService { + + PageResult pageRel(HjcBidProjectParam param); + + List listRel(HjcBidProjectParam param); + + HjcBidProject getByProjectNo(String projectNo); +} diff --git a/src/main/java/com/gxwebsoft/hjc/service/HjcBizService.java b/src/main/java/com/gxwebsoft/hjc/service/HjcBizService.java new file mode 100644 index 0000000..8636d25 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/service/HjcBizService.java @@ -0,0 +1,23 @@ +package com.gxwebsoft.hjc.service; + +import com.gxwebsoft.hjc.dto.HjcOneStopProjectPush; +import com.gxwebsoft.hjc.entity.HjcBidProject; +import com.gxwebsoft.hjc.entity.HjcOrder; + +public interface HjcBizService { + + /** + * 入向:一站式推送标书/中标公告 → 按 projectNo upsert 标书项目 + */ + HjcBidProject upsertFromPush(HjcOneStopProjectPush push, Integer tenantId); + + /** + * 出向:推送订单到一站式 createPurchaseDetails,写推送日志(幂等+重试) + */ + void pushOrderToOneStop(HjcOrder order); + + /** + * 重试失败的推送(幂等) + */ + void retryPendingPush(); +} diff --git a/src/main/java/com/gxwebsoft/hjc/service/HjcEnterpriseMaterialService.java b/src/main/java/com/gxwebsoft/hjc/service/HjcEnterpriseMaterialService.java new file mode 100644 index 0000000..83bfe87 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/service/HjcEnterpriseMaterialService.java @@ -0,0 +1,15 @@ +package com.gxwebsoft.hjc.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.hjc.entity.HjcEnterpriseMaterial; +import com.gxwebsoft.hjc.param.HjcEnterpriseMaterialParam; + +import java.util.List; + +public interface HjcEnterpriseMaterialService extends IService { + + PageResult pageRel(HjcEnterpriseMaterialParam param); + + List listRel(HjcEnterpriseMaterialParam param); +} diff --git a/src/main/java/com/gxwebsoft/hjc/service/HjcEnterpriseService.java b/src/main/java/com/gxwebsoft/hjc/service/HjcEnterpriseService.java new file mode 100644 index 0000000..5a4f70d --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/service/HjcEnterpriseService.java @@ -0,0 +1,17 @@ +package com.gxwebsoft.hjc.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.hjc.entity.HjcEnterprise; +import com.gxwebsoft.hjc.param.HjcEnterpriseParam; + +import java.util.List; + +public interface HjcEnterpriseService extends IService { + + PageResult pageRel(HjcEnterpriseParam param); + + List listRel(HjcEnterpriseParam param); + + HjcEnterprise getByUserId(Integer userId); +} diff --git a/src/main/java/com/gxwebsoft/hjc/service/HjcOrderPushLogService.java b/src/main/java/com/gxwebsoft/hjc/service/HjcOrderPushLogService.java new file mode 100644 index 0000000..e0e30ee --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/service/HjcOrderPushLogService.java @@ -0,0 +1,15 @@ +package com.gxwebsoft.hjc.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.hjc.entity.HjcOrderPushLog; +import com.gxwebsoft.hjc.param.HjcOrderPushLogParam; + +import java.util.List; + +public interface HjcOrderPushLogService extends IService { + + PageResult pageRel(HjcOrderPushLogParam param); + + List listRel(HjcOrderPushLogParam param); +} diff --git a/src/main/java/com/gxwebsoft/hjc/service/HjcOrderService.java b/src/main/java/com/gxwebsoft/hjc/service/HjcOrderService.java new file mode 100644 index 0000000..39d520c --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/service/HjcOrderService.java @@ -0,0 +1,17 @@ +package com.gxwebsoft.hjc.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.hjc.entity.HjcOrder; +import com.gxwebsoft.hjc.param.HjcOrderParam; + +import java.util.List; + +public interface HjcOrderService extends IService { + + PageResult pageRel(HjcOrderParam param); + + List listRel(HjcOrderParam param); + + HjcOrder getByOrderNo(String orderNo); +} diff --git a/src/main/java/com/gxwebsoft/hjc/service/impl/HjcBidProjectServiceImpl.java b/src/main/java/com/gxwebsoft/hjc/service/impl/HjcBidProjectServiceImpl.java new file mode 100644 index 0000000..d71dd6b --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/service/impl/HjcBidProjectServiceImpl.java @@ -0,0 +1,34 @@ +package com.gxwebsoft.hjc.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.hjc.entity.HjcBidProject; +import com.gxwebsoft.hjc.mapper.HjcBidProjectMapper; +import com.gxwebsoft.hjc.param.HjcBidProjectParam; +import com.gxwebsoft.hjc.service.HjcBidProjectService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class HjcBidProjectServiceImpl extends ServiceImpl implements HjcBidProjectService { + + @Override + public PageResult pageRel(HjcBidProjectParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("id desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(HjcBidProjectParam param) { + return baseMapper.selectListRel(param); + } + + @Override + public HjcBidProject getByProjectNo(String projectNo) { + return baseMapper.getByProjectNo(projectNo); + } +} diff --git a/src/main/java/com/gxwebsoft/hjc/service/impl/HjcBizServiceImpl.java b/src/main/java/com/gxwebsoft/hjc/service/impl/HjcBizServiceImpl.java new file mode 100644 index 0000000..7fd3790 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/service/impl/HjcBizServiceImpl.java @@ -0,0 +1,228 @@ +package com.gxwebsoft.hjc.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.gxwebsoft.hjc.dto.CreatePurchaseDetails; +import com.gxwebsoft.hjc.dto.HjcOneStopProjectPush; +import com.gxwebsoft.hjc.entity.HjcBidProject; +import com.gxwebsoft.hjc.entity.HjcEnterprise; +import com.gxwebsoft.hjc.entity.HjcOrder; +import com.gxwebsoft.hjc.entity.HjcOrderPushLog; +import com.gxwebsoft.hjc.service.HjcBidProjectService; +import com.gxwebsoft.hjc.service.HjcBizService; +import com.gxwebsoft.hjc.service.HjcEnterpriseService; +import com.gxwebsoft.hjc.service.HjcOrderService; +import com.gxwebsoft.hjc.service.HjcOrderPushLogService; +import com.gxwebsoft.hjc.util.HjcOneStopAuthUtil; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.client.RestTemplate; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +/** + * 汇吉采一站式双向对接业务 + */ +@Service +public class HjcBizServiceImpl implements HjcBizService { + + private static final DateTimeFormatter DT_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + private static final String STATUS_PAID = "PAID"; + private static final String STATUS_REFUNDED = "REFUNDED"; + + @Value("${hjc.one-stop.base-url:}") + private String oneStopBaseUrl; + + @Value("${hjc.one-stop.create-purchase-details-path:/api/biz/createPurchaseDetails}") + private String createPurchaseDetailsPath; + + @Resource + private HjcBidProjectService hjcBidProjectService; + @Resource + private HjcEnterpriseService hjcEnterpriseService; + @Resource + private HjcOrderService hjcOrderService; + @Resource + private HjcOrderPushLogService hjcOrderPushLogService; + @Resource + private RestTemplate restTemplate; + @Resource + private ObjectMapper objectMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public HjcBidProject upsertFromPush(HjcOneStopProjectPush push, Integer tenantId) { + HjcBidProject project = hjcBidProjectService.getByProjectNo(push.getProjectNo()); + boolean isNew = project == null; + if (isNew) { + project = new HjcBidProject(); + project.setProjectNo(push.getProjectNo()); + project.setTenantId(tenantId); + project.setSaleCount(0); + project.setDataSource("PUSH"); + project.setStatus(1); + } + project.setProjectName(push.getProjectName()); + project.setTenderer(push.getCustomerName()); + project.setWinnerSupplier(push.getSupplierName()); + project.setBidAmount(push.getBidAmount()); + project.setBulletinTitle(push.getBulletinName()); + project.setBulletinContent(push.getContent()); + project.setBulletinFileList(push.getFileList()); + project.setTenderPrice(push.getTenderPrice()); + project.setTenderFile(push.getFiles()); + project.setOnsaleTime(parseDateTime(push.getTenderOnsaleTime())); + project.setOffsaleTime(parseDateTime(push.getTenderOffsaleTime())); + project.setSellingMethod(push.getSellingMethod()); + project.setNeedSell(push.getNeedSellTender()); + project.setDataSource("PUSH"); + if (isNew) { + hjcBidProjectService.save(project); + } else { + hjcBidProjectService.updateById(project); + } + return project; + } + + @Override + public void pushOrderToOneStop(HjcOrder order) { + if (order == null || StrUtil.isBlank(order.getOrderNo())) { + return; + } + HjcOrderPushLog logEntity = new HjcOrderPushLog(); + logEntity.setOrderId(order.getId()); + logEntity.setOrderNo(order.getOrderNo()); + logEntity.setTenantId(order.getTenantId()); + logEntity.setPushStatus(0); + logEntity.setAttemptCount(0); + hjcOrderPushLogService.save(logEntity); + doPush(order, logEntity); + } + + @Override + public void retryPendingPush() { + List pending = hjcOrderPushLogService.list(new LambdaQueryWrapper() + .in(HjcOrderPushLog::getPushStatus, 0, 2) + .and(w -> w.isNull(HjcOrderPushLog::getNextRetryTime) + .or().le(HjcOrderPushLog::getNextRetryTime, LocalDateTime.now())) + .last("limit 50")); + for (HjcOrderPushLog logEntity : pending) { + HjcOrder order = hjcOrderService.getByOrderNo(logEntity.getOrderNo()); + if (order != null) { + doPush(order, logEntity); + } + } + } + + private void doPush(HjcOrder order, HjcOrderPushLog logEntity) { + try { + CreatePurchaseDetails body = buildCreatePurchaseDetails(order); + String payload = objectMapper.writeValueAsString(body); + String ts = HjcOneStopAuthUtil.timestamp(); + String sign = HjcOneStopAuthUtil.sign(ts); + + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.set("appKey", HjcOneStopAuthUtil.APP_KEY); + headers.set("timestamp", ts); + headers.set("sign", sign); + + String url = oneStopBaseUrl + createPurchaseDetailsPath; + ResponseEntity resp = restTemplate.postForEntity(url, new HttpEntity<>(payload, headers), String.class); + + logEntity.setPayload(payload); + logEntity.setAttemptCount(logEntity.getAttemptCount() + 1); + logEntity.setHttpCode(resp.getStatusCode().value()); + logEntity.setResponseBody(limitStr(resp.getBody(), 3000)); + if (resp.getStatusCode().is2xxSuccessful()) { + logEntity.setPushStatus(1); + logEntity.setErrorMsg(null); + logEntity.setNextRetryTime(null); + } else { + logEntity.setPushStatus(2); + logEntity.setErrorMsg("HTTP " + resp.getStatusCode().value()); + logEntity.setNextRetryTime(LocalDateTime.now().plusMinutes(30)); + } + } catch (Exception e) { + logEntity.setAttemptCount(logEntity.getAttemptCount() + 1); + logEntity.setPushStatus(2); + logEntity.setErrorMsg(limitStr(e.getMessage(), 1000)); + logEntity.setNextRetryTime(LocalDateTime.now().plusMinutes(30)); + } + hjcOrderPushLogService.updateById(logEntity); + } + + private CreatePurchaseDetails buildCreatePurchaseDetails(HjcOrder order) { + CreatePurchaseDetails body = new CreatePurchaseDetails(); + body.setIdempotencyKey("HJC_ORD_" + order.getOrderNo()); + body.setOrderNo(order.getOrderNo()); + body.setProjectNo(order.getProjectNo()); + body.setProjectName(order.getProjectName()); + body.setTenderPrice(order.getUnitPrice()); + body.setQuantity(order.getQuantity()); + body.setTotalAmount(order.getTotalAmount()); + body.setPaidAt(order.getPayTime() == null ? null : order.getPayTime().format(DT_FMT)); + body.setPayMethod(order.getPayMethod()); + body.setStatus(order.getPayStatus() != null && order.getPayStatus() == 3 ? STATUS_REFUNDED : STATUS_PAID); + body.setInvoiceStatus(invoiceStatus(order.getInvoiceStatus())); + + CreatePurchaseDetails.Buyer buyer = new CreatePurchaseDetails.Buyer(); + buyer.setEnterpriseName(order.getEnterpriseName()); + buyer.setContactName(order.getContactName()); + buyer.setContactPhone(order.getContactPhone()); + buyer.setContactEmail(order.getContactEmail()); + if (order.getEnterpriseId() != null) { + HjcEnterprise enterprise = hjcEnterpriseService.getById(order.getEnterpriseId()); + if (enterprise != null) { + buyer.setCreditCode(enterprise.getCreditCode()); + } + } + body.setBuyer(buyer); + return body; + } + + private String invoiceStatus(Integer invoiceStatus) { + if (invoiceStatus == null) { + return "NONE"; + } + switch (invoiceStatus) { + case 1: return "APPLIED"; + case 2: return "ISSUED"; + default: return "NONE"; + } + } + + private LocalDateTime parseDateTime(String text) { + if (StrUtil.isBlank(text)) { + return null; + } + String t = text.trim(); + try { + if (t.length() == 14) { + return LocalDateTime.parse(t, DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); + } + if (t.contains("T")) { + return LocalDateTime.parse(t); + } + return LocalDateTime.parse(t, DT_FMT); + } catch (Exception e) { + return null; + } + } + + private String limitStr(String s, int max) { + if (s == null) { + return null; + } + return s.length() > max ? s.substring(0, max) : s; + } +} diff --git a/src/main/java/com/gxwebsoft/hjc/service/impl/HjcEnterpriseMaterialServiceImpl.java b/src/main/java/com/gxwebsoft/hjc/service/impl/HjcEnterpriseMaterialServiceImpl.java new file mode 100644 index 0000000..989d51f --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/service/impl/HjcEnterpriseMaterialServiceImpl.java @@ -0,0 +1,29 @@ +package com.gxwebsoft.hjc.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.hjc.entity.HjcEnterpriseMaterial; +import com.gxwebsoft.hjc.mapper.HjcEnterpriseMaterialMapper; +import com.gxwebsoft.hjc.param.HjcEnterpriseMaterialParam; +import com.gxwebsoft.hjc.service.HjcEnterpriseMaterialService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class HjcEnterpriseMaterialServiceImpl extends ServiceImpl implements HjcEnterpriseMaterialService { + + @Override + public PageResult pageRel(HjcEnterpriseMaterialParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("id desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(HjcEnterpriseMaterialParam param) { + return baseMapper.selectListRel(param); + } +} diff --git a/src/main/java/com/gxwebsoft/hjc/service/impl/HjcEnterpriseServiceImpl.java b/src/main/java/com/gxwebsoft/hjc/service/impl/HjcEnterpriseServiceImpl.java new file mode 100644 index 0000000..4987f34 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/service/impl/HjcEnterpriseServiceImpl.java @@ -0,0 +1,34 @@ +package com.gxwebsoft.hjc.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.hjc.entity.HjcEnterprise; +import com.gxwebsoft.hjc.mapper.HjcEnterpriseMapper; +import com.gxwebsoft.hjc.param.HjcEnterpriseParam; +import com.gxwebsoft.hjc.service.HjcEnterpriseService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class HjcEnterpriseServiceImpl extends ServiceImpl implements HjcEnterpriseService { + + @Override + public PageResult pageRel(HjcEnterpriseParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("id desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(HjcEnterpriseParam param) { + return baseMapper.selectListRel(param); + } + + @Override + public HjcEnterprise getByUserId(Integer userId) { + return baseMapper.getByUserId(userId); + } +} diff --git a/src/main/java/com/gxwebsoft/hjc/service/impl/HjcOrderPushLogServiceImpl.java b/src/main/java/com/gxwebsoft/hjc/service/impl/HjcOrderPushLogServiceImpl.java new file mode 100644 index 0000000..7ed3bd6 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/service/impl/HjcOrderPushLogServiceImpl.java @@ -0,0 +1,29 @@ +package com.gxwebsoft.hjc.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.hjc.entity.HjcOrderPushLog; +import com.gxwebsoft.hjc.mapper.HjcOrderPushLogMapper; +import com.gxwebsoft.hjc.param.HjcOrderPushLogParam; +import com.gxwebsoft.hjc.service.HjcOrderPushLogService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class HjcOrderPushLogServiceImpl extends ServiceImpl implements HjcOrderPushLogService { + + @Override + public PageResult pageRel(HjcOrderPushLogParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("id desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(HjcOrderPushLogParam param) { + return baseMapper.selectListRel(param); + } +} diff --git a/src/main/java/com/gxwebsoft/hjc/service/impl/HjcOrderServiceImpl.java b/src/main/java/com/gxwebsoft/hjc/service/impl/HjcOrderServiceImpl.java new file mode 100644 index 0000000..c4fac80 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/service/impl/HjcOrderServiceImpl.java @@ -0,0 +1,34 @@ +package com.gxwebsoft.hjc.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.web.PageParam; +import com.gxwebsoft.common.core.web.PageResult; +import com.gxwebsoft.hjc.entity.HjcOrder; +import com.gxwebsoft.hjc.mapper.HjcOrderMapper; +import com.gxwebsoft.hjc.param.HjcOrderParam; +import com.gxwebsoft.hjc.service.HjcOrderService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class HjcOrderServiceImpl extends ServiceImpl implements HjcOrderService { + + @Override + public PageResult pageRel(HjcOrderParam param) { + PageParam page = new PageParam<>(param); + page.setDefaultOrder("id desc"); + List list = baseMapper.selectPageRel(page, param); + return new PageResult<>(list, page.getTotal()); + } + + @Override + public List listRel(HjcOrderParam param) { + return baseMapper.selectListRel(param); + } + + @Override + public HjcOrder getByOrderNo(String orderNo) { + return baseMapper.getByOrderNo(orderNo); + } +} diff --git a/src/main/java/com/gxwebsoft/hjc/util/HjcOneStopAuthUtil.java b/src/main/java/com/gxwebsoft/hjc/util/HjcOneStopAuthUtil.java new file mode 100644 index 0000000..6a50018 --- /dev/null +++ b/src/main/java/com/gxwebsoft/hjc/util/HjcOneStopAuthUtil.java @@ -0,0 +1,53 @@ +package com.gxwebsoft.hjc.util; + +import cn.hutool.crypto.SecureUtil; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * 汇吉采 → 一站式平台 推送鉴权工具。 + * 规则:sign = MD5(appKey + password + timestamp),timestamp = yyyyMMddHHmm(北京时)。 + * 详见 mp-java/docs/一站式平台推送-接口鉴权规范.md + */ +public final class HjcOneStopAuthUtil { + + public static final String APP_KEY = "HJC_Official_Website"; + public static final String PASSWORD = "vQ8$kR3#mW6@xP2!nF"; + + private static final DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyyMMddHHmm"); + + private HjcOneStopAuthUtil() { + } + + /** 当前北京时间,yyyyMMddHHmm */ + public static String timestamp() { + return LocalDateTime.now().format(FMT); + } + + /** 计算签名 sign = MD5(appKey + password + timestamp),小写 32 位 */ + public static String sign(String timestamp) { + return SecureUtil.md5(APP_KEY + PASSWORD + timestamp); + } + + /** 校验请求头中的 sign 是否符合 appKey/password/timestamp 约定 */ + public static boolean verify(String appKey, String timestamp, String sign) { + if (appKey == null || timestamp == null || sign == null) { + return false; + } + if (!APP_KEY.equals(appKey)) { + return false; + } + // 时间窗口 ±10 分钟,防重放 + LocalDateTime ts; + try { + ts = LocalDateTime.parse(timestamp, FMT); + } catch (Exception e) { + return false; + } + if (Math.abs(java.time.Duration.between(ts, LocalDateTime.now()).toMinutes()) > 10) { + return false; + } + return sign.equalsIgnoreCase(sign(timestamp)); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6ef13b1..3c1c894 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -182,3 +182,10 @@ house: url: "https://mcp.amap.com/mcp?key=7fb25e6f0dbf19ff947ba6366b11a478" timeout-ms: 20000 tool-cache-ttl-ms: 300000 + +# 汇吉采一站式平台对接 +hjc: + one-stop: + # 一站式平台地址(+ path = 最终推送地址)。base-url 为空时推送不会发起,部署时需配置。 + base-url: "" + create-purchase-details-path: /api/biz/createPurchaseDetails diff --git a/src/main/resources/sql/hjc_init.sql b/src/main/resources/sql/hjc_init.sql new file mode 100644 index 0000000..7d85dfd --- /dev/null +++ b/src/main/resources/sql/hjc_init.sql @@ -0,0 +1,137 @@ +-- ============================================================ +-- 汇吉采标书购买平台 初始化 DDL (mp-api / com.gxwebsoft.hjc) +-- 约定:engine=InnoDB, charset=utf8mb4, 主键 id int 自增 +-- 公共列 tenant_id / deleted / create_time / update_time +-- 说明:项目与标书为同一实体(甲方确认一个项目一本标书),单表 hjc_bid_project。 +-- ============================================================ + +-- ---------- 项目/标书(单一实体:项目即标书) ---------- +CREATE TABLE `hjc_bid_project` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `project_no` varchar(64) NOT NULL COMMENT '项目编号(upsert 键,一站式推送用)', + `project_name` varchar(255) NOT NULL COMMENT '项目名称', + `category` varchar(32) DEFAULT NULL COMMENT '项目分类:服务类/工程类/货物类', + `publish_time` datetime DEFAULT NULL COMMENT '发布时间', + `deadline_time` datetime DEFAULT NULL COMMENT '投标截止时间', + `tenderer` varchar(128) DEFAULT NULL COMMENT '招标人(customerName)', + `winner_supplier` varchar(128) DEFAULT NULL COMMENT '中标公司(supplierName)', + `bid_amount` decimal(18,2) DEFAULT NULL COMMENT '中标金额(bidAmount)', + `bulletin_title` varchar(255) DEFAULT NULL COMMENT '公告标题(bulletinName)', + `bulletin_content` text COMMENT '公告正文(content)', + `bulletin_file_list` text COMMENT '公告附件(fileList, JSON数组字符串)', + `tender_price` decimal(18,2) DEFAULT NULL COMMENT '标书价格/信息服务费(tenderPrice)', + `tender_file` text COMMENT '标书附件(files, JSON数组字符串)', + `onsale_time` datetime DEFAULT NULL COMMENT '开售时间(tenderOnsaleTime)', + `offsale_time` datetime DEFAULT NULL COMMENT '停售时间(tenderOffsaleTime)', + `selling_method` tinyint(4) DEFAULT NULL COMMENT '售卖方式:1公司财务 2公众号 3交易中心 4政采云', + `need_sell` tinyint(1) DEFAULT 0 COMMENT '是否卖标书(needSellTender):0否 1是', + `status` tinyint(4) DEFAULT 1 COMMENT '状态:1上架(onsale) 0下架/停售(ended)', + `data_source` varchar(16) DEFAULT 'MANUAL' COMMENT '来源:PUSH一站式推送 / MANUAL后台手工', + `sale_count` int(11) DEFAULT 0 COMMENT '已售数量', + `tenant_id` int(11) DEFAULT NULL COMMENT '租户ID', + `deleted` tinyint(1) DEFAULT 0 COMMENT '是否删除, 0否, 1是', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `idx_hjc_bp_project_no` (`project_no`), + KEY `idx_hjc_bp_status` (`status`), + KEY `idx_hjc_bp_category` (`category`), + KEY `idx_hjc_bp_tenant` (`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='汇吉采标书项目(项目即标书,单表)'; + +-- ---------- 企业账号(关联 common.system.user) ---------- +CREATE TABLE `hjc_enterprise` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `user_id` int(11) NOT NULL COMMENT '关联登录用户ID(common user)', + `name` varchar(255) NOT NULL COMMENT '企业名称', + `credit_code` varchar(64) DEFAULT NULL COMMENT '纳税人识别号/统一社会信用代码', + `contact_phone` varchar(32) DEFAULT NULL COMMENT '企业联系电话', + `contact_email` varchar(128) DEFAULT NULL COMMENT '企业邮箱', + `address` varchar(255) DEFAULT NULL COMMENT '企业地址', + `agent_name` varchar(64) DEFAULT NULL COMMENT '经办人姓名', + `agent_email` varchar(128) DEFAULT NULL COMMENT '经办人邮箱', + `agent_phone` varchar(32) DEFAULT NULL COMMENT '经办人手机号', + `authorize_expire` datetime DEFAULT NULL COMMENT '授权委托书到期时间', + `auth_status` tinyint(4) DEFAULT 0 COMMENT '资质状态:0待审核 1已通过 2已驳回', + `reject_reason` varchar(500) DEFAULT NULL COMMENT '驳回原因', + `tenant_id` int(11) DEFAULT NULL COMMENT '租户ID', + `deleted` tinyint(1) DEFAULT 0 COMMENT '是否删除, 0否, 1是', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_hjc_ent_user` (`user_id`), + KEY `idx_hjc_ent_credit` (`credit_code`), + KEY `idx_hjc_ent_auth` (`auth_status`), + KEY `idx_hjc_ent_tenant` (`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='汇吉采企业账号与资质'; + +-- ---------- 企业资质证件材料 ---------- +CREATE TABLE `hjc_enterprise_material` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `enterprise_id` int(11) NOT NULL COMMENT '企业ID', + `material_type` varchar(32) NOT NULL COMMENT '材料类型:idcard_front/idcard_back/handbook/license', + `material_name` varchar(128) DEFAULT NULL COMMENT '材料名称', + `file_url` varchar(500) NOT NULL COMMENT '文件地址', + `tenant_id` int(11) DEFAULT NULL COMMENT '租户ID', + `deleted` tinyint(1) DEFAULT 0 COMMENT '是否删除, 0否, 1是', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `idx_hjc_entm_ent` (`enterprise_id`), + KEY `idx_hjc_entm_tenant` (`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='汇吉采企业资质证件材料'; + +-- ---------- 标书订单 ---------- +CREATE TABLE `hjc_order` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `order_no` varchar(64) NOT NULL COMMENT '订单号', + `project_id` int(11) NOT NULL COMMENT '标书项目ID', + `project_no` varchar(64) DEFAULT NULL COMMENT '项目编号(冗余)', + `project_name` varchar(255) DEFAULT NULL COMMENT '项目名称(冗余)', + `enterprise_id` int(11) NOT NULL COMMENT '购买企业ID', + `enterprise_name` varchar(255) DEFAULT NULL COMMENT '购买企业名称(冗余)', + `contact_name` varchar(64) DEFAULT NULL COMMENT '购买联系人', + `contact_phone` varchar(32) DEFAULT NULL COMMENT '购买联系电话', + `contact_email` varchar(128) DEFAULT NULL COMMENT '购买联系邮箱', + `quantity` int(11) DEFAULT 1 COMMENT '购买数量', + `unit_price` decimal(18,2) DEFAULT NULL COMMENT '单价(信息服务费)', + `total_amount` decimal(18,2) DEFAULT NULL COMMENT '订单总额', + `pay_method` varchar(32) DEFAULT NULL COMMENT '支付方式:WECHAT_NATIVE/ALIPAY', + `pay_time` datetime DEFAULT NULL COMMENT '支付时间', + `pay_status` tinyint(4) DEFAULT 0 COMMENT '支付状态:0待支付 1支付成功 2支付失败 3已退款', + `order_status` tinyint(4) DEFAULT 0 COMMENT '订单状态:0待支付 1已完成 2已取消', + `invoice_status` tinyint(4) DEFAULT 0 COMMENT '开票状态:0未开票 1已申请 2已开票', + `tenant_id` int(11) DEFAULT NULL COMMENT '租户ID', + `deleted` tinyint(1) DEFAULT 0 COMMENT '是否删除, 0否, 1是', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_hjc_order_no` (`order_no`), + KEY `idx_hjc_order_user` (`enterprise_id`), + KEY `idx_hjc_order_project` (`project_id`), + KEY `idx_hjc_order_pay` (`pay_status`), + KEY `idx_hjc_order_tenant` (`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='汇吉采标书订单'; + +-- ---------- 一站式出向推送日志(幂等+重试) ---------- +CREATE TABLE `hjc_order_push_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `order_id` int(11) NOT NULL COMMENT '订单ID', + `order_no` varchar(64) NOT NULL COMMENT '订单号(一站式幂等键)', + `payload` text COMMENT '推送请求体(JSON)', + `push_status` tinyint(4) DEFAULT 0 COMMENT '推送状态:0待推送 1成功 2失败', + `http_code` int(11) DEFAULT NULL COMMENT '一站式HTTP状态码', + `response_body` text COMMENT '一站式返回内容', + `error_msg` varchar(1000) DEFAULT NULL COMMENT '失败原因', + `attempt_count` int(11) DEFAULT 0 COMMENT '已尝试次数', + `next_retry_time` datetime DEFAULT NULL COMMENT '下次重试时间', + `tenant_id` int(11) DEFAULT NULL COMMENT '租户ID', + `deleted` tinyint(1) DEFAULT 0 COMMENT '是否删除, 0否, 1是', + `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`), + KEY `idx_hjc_push_order` (`order_id`), + KEY `idx_hjc_push_order_no` (`order_no`), + KEY `idx_hjc_push_status` (`push_status`), + KEY `idx_hjc_push_tenant` (`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='汇吉采一站式订单推送日志';