v1.0.31 #43
@@ -81,6 +81,8 @@ public enum GaoPermissionCode implements BuiltinPermissionCode {
|
||||
|
||||
SALES_ORDER_READ("SALES_ORDER:READ", "销售订单读取", true, true),
|
||||
|
||||
SALES_ORDER_UPDATE("SALES_ORDER:UPDATE", "销售订单修改", true, true),
|
||||
|
||||
SALES_ORDER_CANCEL("SALES_ORDER:CANCEL", "销售订单取消", true, true),
|
||||
|
||||
SALES_ORDER_PRICE_OVERRIDE("SALES_ORDER:PRICE_OVERRIDE", "销售订单价格修改", true, true),
|
||||
|
||||
+25
-1
@@ -8,6 +8,7 @@ import com.imyeyu.api.modules.gao.entity.GaoCustomer;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoCustomerPackage;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoCustomerPackageItem;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoOrderFulfillment;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoProduct;
|
||||
import com.imyeyu.api.modules.gao.service.GaoCustomerPackageService;
|
||||
import com.imyeyu.api.modules.gao.service.GaoCustomerService;
|
||||
import com.imyeyu.api.modules.gao.service.GaoOrderFulfillmentService;
|
||||
@@ -127,11 +128,34 @@ public class GaoCustomerPackageController {
|
||||
Map<String, User> userMap = userIdList.isEmpty() ? Map.of() : userService.mapByIdList(userIdList);
|
||||
for (GaoCustomerPackage packageEntity : packageList) {
|
||||
List<GaoCustomerPackageItem> itemList = itemMap.getOrDefault(packageEntity.getId(), List.of());
|
||||
fillItemAttachments(itemList);
|
||||
for (GaoCustomerPackageItem item : itemList) {
|
||||
fillDerived(item);
|
||||
}
|
||||
packageEntity.setItemList(itemList);
|
||||
packageEntity.setCancelOperator(userMap.get(packageEntity.getCancelOperatorUserId()));
|
||||
String cancelOperatorUserId = packageEntity.getCancelOperatorUserId();
|
||||
packageEntity.setCancelOperator(cancelOperatorUserId == null ? null : userMap.get(cancelOperatorUserId));
|
||||
}
|
||||
}
|
||||
|
||||
private void fillItemAttachments(List<GaoCustomerPackageItem> itemList) {
|
||||
if (itemList == null || itemList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<String> productIdList = itemList.stream()
|
||||
.map(GaoCustomerPackageItem::getProductId)
|
||||
.filter(value -> value != null && !value.isBlank())
|
||||
.distinct()
|
||||
.toList();
|
||||
if (productIdList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Map<String, List<Attachment>> attachmentMap = attachmentService.mapByBizIdList(
|
||||
Attachment.BizType.GAO_PRODUCT,
|
||||
productIdList,
|
||||
GaoProduct.AttachType.PHOTO.name());
|
||||
for (GaoCustomerPackageItem item : itemList) {
|
||||
item.setAttachmentList(attachmentMap.getOrDefault(item.getProductId(), List.of()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,8 +60,7 @@ public class GaoFundRecordController {
|
||||
@RequireGaoPermission(GaoPermissionCode.FUND_RECORD_READ)
|
||||
@PostMapping("/detail")
|
||||
public GaoFundRecord detail(@RequestParam String id) {
|
||||
GaoFundRecord result = service.get(id);
|
||||
TimiException.required(result, "not found fund record");
|
||||
GaoFundRecord result = service.detail(id);
|
||||
storeScopeService.checkStoreId(result.getStoreId());
|
||||
fillTransient(List.of(result));
|
||||
return result;
|
||||
|
||||
+17
@@ -4,7 +4,9 @@ import com.imyeyu.api.modules.common.entity.Attachment;
|
||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||
import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoCustomer;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoOrderFulfillment;
|
||||
import com.imyeyu.api.modules.gao.service.GaoCustomerService;
|
||||
import com.imyeyu.api.modules.gao.service.GaoOrderFulfillmentService;
|
||||
import com.imyeyu.api.modules.gao.service.GaoStoreScopeService;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoOrderFulfillmentActionRequest;
|
||||
@@ -41,6 +43,7 @@ public class GaoOrderFulfillmentController {
|
||||
private final GaoOrderFulfillmentService service;
|
||||
private final GaoStoreScopeService storeScopeService;
|
||||
private final AttachmentService attachmentService;
|
||||
private final GaoCustomerService customerService;
|
||||
private final UserService userService;
|
||||
|
||||
@AOPLog
|
||||
@@ -131,6 +134,15 @@ public class GaoOrderFulfillmentController {
|
||||
}
|
||||
List<String> idList = fulfillmentList.stream().map(GaoOrderFulfillment::getId).toList();
|
||||
Map<String, List<Attachment>> attachmentMap = attachmentService.mapByBizIdList(Attachment.BizType.GAO_ORDER_FULFILLMENT, idList);
|
||||
List<String> customerIdList = fulfillmentList.stream()
|
||||
.map(GaoOrderFulfillment::getCustomerId)
|
||||
.filter(value -> value != null && !value.isBlank())
|
||||
.distinct()
|
||||
.toList();
|
||||
Map<String, GaoCustomer> customerMap = customerIdList.isEmpty() ? Map.of() : customerService.mapByIdList(customerIdList);
|
||||
Map<String, List<Attachment>> customerAttachmentMap = customerIdList.isEmpty()
|
||||
? Map.of()
|
||||
: attachmentService.mapByBizIdList(Attachment.BizType.GAO_CUSTOMER, customerIdList, GaoCustomer.AttachType.PHOTO.name());
|
||||
List<String> userIdList = fulfillmentList.stream()
|
||||
.flatMap(item -> Stream.of(item.getOperatorUserId(), item.getVerifierUserId()))
|
||||
.filter(value -> value != null && !value.isBlank())
|
||||
@@ -139,6 +151,11 @@ public class GaoOrderFulfillmentController {
|
||||
Map<String, User> userMap = userIdList.isEmpty() ? Map.of() : userService.mapByIdList(userIdList);
|
||||
for (GaoOrderFulfillment fulfillment : fulfillmentList) {
|
||||
fulfillment.setAttachmentList(attachmentMap.getOrDefault(fulfillment.getId(), List.of()));
|
||||
GaoCustomer customer = customerMap.get(fulfillment.getCustomerId());
|
||||
if (customer != null) {
|
||||
customer.setAttachmentList(customerAttachmentMap.getOrDefault(customer.getId(), List.of()));
|
||||
}
|
||||
fulfillment.setCustomer(customer);
|
||||
fulfillment.setOperator(userMap.get(fulfillment.getOperatorUserId()));
|
||||
fulfillment.setVerifier(userMap.get(fulfillment.getVerifierUserId()));
|
||||
}
|
||||
|
||||
+29
-4
@@ -4,8 +4,10 @@ import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoPackageConfig;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoPackageConfigItem;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoProduct;
|
||||
import com.imyeyu.api.modules.gao.service.GaoEventService;
|
||||
import com.imyeyu.api.modules.gao.service.GaoPackageConfigService;
|
||||
import com.imyeyu.api.modules.gao.service.GaoProductService;
|
||||
import com.imyeyu.api.modules.gao.service.GaoStoreScopeService;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoPackageConfigPage;
|
||||
import com.imyeyu.api.modules.user.entity.User;
|
||||
@@ -35,6 +37,7 @@ public class GaoPackageConfigController {
|
||||
|
||||
private final GaoPackageConfigService service;
|
||||
private final GaoEventService eventService;
|
||||
private final GaoProductService productService;
|
||||
private final GaoStoreScopeService storeScopeService;
|
||||
private final UserService userService;
|
||||
|
||||
@@ -46,7 +49,7 @@ public class GaoPackageConfigController {
|
||||
TimiException.required(page, "not found page");
|
||||
page.setStoreId(storeScopeService.resolveStoreId(page.getStoreId()));
|
||||
PageResult<GaoPackageConfig> result = service.pageByQuery(page);
|
||||
fillTransient(result.getList());
|
||||
fillTransient(result.getList(), false);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -56,7 +59,7 @@ public class GaoPackageConfigController {
|
||||
@PostMapping("/list/valid")
|
||||
public List<GaoPackageConfig> listValid(@RequestParam String storeId) {
|
||||
List<GaoPackageConfig> result = service.listValid(storeScopeService.resolveStoreId(storeId));
|
||||
fillTransient(result);
|
||||
fillTransient(result, false);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -68,11 +71,11 @@ public class GaoPackageConfigController {
|
||||
GaoPackageConfig config = service.get(id);
|
||||
TimiException.required(config, "not found package config");
|
||||
storeScopeService.checkStoreId(config.getStoreId());
|
||||
fillTransient(List.of(config));
|
||||
fillTransient(List.of(config), true);
|
||||
return config;
|
||||
}
|
||||
|
||||
private void fillTransient(List<GaoPackageConfig> configList) {
|
||||
private void fillTransient(List<GaoPackageConfig> configList, boolean includeProductDetail) {
|
||||
if (configList == null || configList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -83,6 +86,28 @@ public class GaoPackageConfigController {
|
||||
config.setItemList(itemMap.getOrDefault(config.getId(), List.of()));
|
||||
config.setUpdater(updaterMap.get(config.getUpdatedBy()));
|
||||
}
|
||||
if (includeProductDetail) {
|
||||
fillProductDetails(configList);
|
||||
}
|
||||
}
|
||||
|
||||
private void fillProductDetails(List<GaoPackageConfig> configList) {
|
||||
List<String> productIdList = configList.stream()
|
||||
.flatMap(config -> config.getItemList().stream())
|
||||
.map(GaoPackageConfigItem::getProductId)
|
||||
.filter(value -> value != null && !value.isBlank())
|
||||
.distinct()
|
||||
.toList();
|
||||
if (productIdList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Map<String, GaoProduct> productMap = productService.listByIdList(productIdList).stream()
|
||||
.collect(java.util.stream.Collectors.toMap(GaoProduct::getId, item -> item));
|
||||
for (GaoPackageConfig config : configList) {
|
||||
for (GaoPackageConfigItem item : config.getItemList()) {
|
||||
item.setProduct(productMap.get(item.getProductId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.imyeyu.api.modules.gao.vo.GaoOrderPaymentRefundRequest;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoOrderPaymentRevokeRequest;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoSalesOrderCancelRequest;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoSalesOrderPage;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoSalesOrderUpdateRequest;
|
||||
import com.imyeyu.java.bean.timi.TimiException;
|
||||
import com.imyeyu.spring.annotation.AOPLog;
|
||||
import com.imyeyu.spring.annotation.RequestRateLimit;
|
||||
@@ -67,6 +68,16 @@ public class GaoSalesOrderController {
|
||||
return service.createDirectProductOrder(request);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequestRateLimit
|
||||
@RequireGaoPermission(GaoPermissionCode.SALES_ORDER_UPDATE)
|
||||
@PostMapping("/update")
|
||||
public GaoSalesOrder update(@RequestBody GaoSalesOrderUpdateRequest request) {
|
||||
TimiException.required(request, "not found sales order update request");
|
||||
TimiException.required(request.getId(), "not found sales order.id");
|
||||
return service.updateRemarkAndAttachments(request);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequestRateLimit
|
||||
@RequireGaoPermission(GaoPermissionCode.SALES_ORDER_CANCEL)
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package com.imyeyu.api.modules.gao.entity;
|
||||
|
||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||
import com.imyeyu.spring.annotation.table.Transient;
|
||||
import com.imyeyu.spring.entity.UUIDEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/// GAO 客户套餐产品权益快照
|
||||
///
|
||||
@@ -24,6 +26,10 @@ public class GaoCustomerPackageItem extends UUIDEntity {
|
||||
/// 产品单位 ID
|
||||
private String productUnitId;
|
||||
|
||||
/// 产品图片附件
|
||||
@Transient
|
||||
private List<Attachment> attachmentList;
|
||||
|
||||
/// 产品名称快照
|
||||
private String productNameSnapshot;
|
||||
|
||||
|
||||
@@ -101,6 +101,17 @@ public class GaoFundRecord extends UUIDEntity {
|
||||
/// 备注
|
||||
private String remark;
|
||||
|
||||
/// 关联的冲正流水 ID
|
||||
@Transient
|
||||
private String revokeRecordId;
|
||||
|
||||
/// 关联销售订单总价,单位分
|
||||
@Transient
|
||||
private Long salesOrderAmount;
|
||||
|
||||
/// 流水发生时关联销售订单剩余待收款金额快照,单位分
|
||||
private Long salesOrderUnpaidAmountSnapshot;
|
||||
|
||||
/// 操作人
|
||||
@Transient
|
||||
private User operator;
|
||||
|
||||
@@ -2,8 +2,13 @@ package com.imyeyu.api.modules.gao.entity;
|
||||
|
||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||
import com.imyeyu.api.modules.user.entity.User;
|
||||
import com.imyeyu.spring.annotation.table.AutoUUID;
|
||||
import com.imyeyu.spring.annotation.table.Id;
|
||||
import com.imyeyu.spring.annotation.table.Transient;
|
||||
import com.imyeyu.spring.entity.Creatable;
|
||||
import com.imyeyu.spring.entity.IDEntity;
|
||||
import com.imyeyu.spring.entity.UUIDEntity;
|
||||
import com.imyeyu.spring.entity.Updatable;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@@ -14,8 +19,7 @@ import java.util.List;
|
||||
/// @author Codex
|
||||
/// @since 2026-09-02
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class GaoOrderFulfillment extends UUIDEntity {
|
||||
public class GaoOrderFulfillment implements IDEntity<String>, Creatable, Updatable {
|
||||
|
||||
/// 履约来源类型
|
||||
public enum FulfillmentType {
|
||||
@@ -49,6 +53,10 @@ public class GaoOrderFulfillment extends UUIDEntity {
|
||||
REVOKED
|
||||
}
|
||||
|
||||
@Id
|
||||
@AutoUUID
|
||||
private String id;
|
||||
|
||||
/// 销售订单 ID
|
||||
private String salesOrderId;
|
||||
|
||||
@@ -88,10 +96,18 @@ public class GaoOrderFulfillment extends UUIDEntity {
|
||||
/// 备注
|
||||
private String remark;
|
||||
|
||||
private Long createdAt;
|
||||
|
||||
private Long updatedAt;
|
||||
|
||||
/// 提交人
|
||||
@Transient
|
||||
private User operator;
|
||||
|
||||
/// 客户
|
||||
@Transient
|
||||
private GaoCustomer customer;
|
||||
|
||||
/// 核销或拒绝操作人
|
||||
@Transient
|
||||
private User verifier;
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
package com.imyeyu.api.modules.gao.entity;
|
||||
|
||||
import com.imyeyu.spring.entity.UUIDEntity;
|
||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||
import com.imyeyu.spring.annotation.table.AutoUUID;
|
||||
import com.imyeyu.spring.annotation.table.Id;
|
||||
import com.imyeyu.spring.annotation.table.Transient;
|
||||
import com.imyeyu.spring.entity.Creatable;
|
||||
import com.imyeyu.spring.entity.IDEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/// GAO 统一履约明细
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-09-02
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class GaoOrderFulfillmentItem extends UUIDEntity {
|
||||
public class GaoOrderFulfillmentItem implements IDEntity<String>, Creatable {
|
||||
|
||||
@Id
|
||||
@AutoUUID
|
||||
private String id;
|
||||
|
||||
/// 履约单 ID
|
||||
private String fulfillmentId;
|
||||
@@ -23,6 +31,10 @@ public class GaoOrderFulfillmentItem extends UUIDEntity {
|
||||
/// 产品单位 ID
|
||||
private String productUnitId;
|
||||
|
||||
/// 产品图片附件
|
||||
@Transient
|
||||
private List<Attachment> attachmentList;
|
||||
|
||||
/// 直接订单明细 ID
|
||||
private String sourceOrderItemId;
|
||||
|
||||
@@ -55,4 +67,6 @@ public class GaoOrderFulfillmentItem extends UUIDEntity {
|
||||
|
||||
/// 基础单位数量系数快照
|
||||
private BigDecimal baseQuantityPerUnitSnapshot;
|
||||
|
||||
private Long createdAt;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.imyeyu.api.modules.gao.entity;
|
||||
|
||||
import com.imyeyu.spring.annotation.table.Transient;
|
||||
import com.imyeyu.spring.entity.UUIDEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -40,4 +41,8 @@ public class GaoPackageConfigItem extends UUIDEntity {
|
||||
|
||||
/// 备注
|
||||
private String remark;
|
||||
|
||||
/// 产品详情
|
||||
@Transient
|
||||
private GaoProduct product;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package com.imyeyu.api.modules.gao.entity;
|
||||
|
||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||
import com.imyeyu.spring.annotation.table.Transient;
|
||||
import com.imyeyu.spring.entity.UUIDEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/// GAO 直接产品订单明细
|
||||
///
|
||||
@@ -23,6 +26,10 @@ public class GaoSalesOrderItem extends UUIDEntity {
|
||||
/// 产品单位 ID
|
||||
private String productUnitId;
|
||||
|
||||
/// 产品图片附件
|
||||
@Transient
|
||||
private List<Attachment> attachmentList;
|
||||
|
||||
/// 产品名称快照
|
||||
private String productNameSnapshot;
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ public interface GaoFundRecordMapper extends BaseMapper<GaoFundRecord, String> {
|
||||
/// 锁定资金记录
|
||||
GaoFundRecord selectForUpdate(@Param("id") String id);
|
||||
|
||||
/// 查询资金记录及关联销售订单资金摘要
|
||||
GaoFundRecord selectWithSalesOrderSummary(@Param("id") String id);
|
||||
|
||||
/// 查询资金冲正记录
|
||||
GaoFundRecord selectRevokeBySourceRecordId(@Param("sourceRecordId") String sourceRecordId);
|
||||
|
||||
|
||||
@@ -15,6 +15,9 @@ public interface GaoOrderFulfillmentItemMapper extends BaseMapper<GaoOrderFulfil
|
||||
/// 按履约单查询明细
|
||||
List<GaoOrderFulfillmentItem> selectByFulfillmentId(@Param("fulfillmentId") String fulfillmentId);
|
||||
|
||||
/// 批量查询履约明细
|
||||
List<GaoOrderFulfillmentItem> selectByFulfillmentIdList(@Param("fulfillmentIdList") List<String> fulfillmentIdList);
|
||||
|
||||
/// 锁定履约明细
|
||||
List<GaoOrderFulfillmentItem> selectByFulfillmentIdForUpdate(@Param("fulfillmentId") String fulfillmentId);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.imyeyu.api.modules.gao.vo.GaoProductPage;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/// GAO 产品 Mapper
|
||||
@@ -19,6 +20,9 @@ public interface GaoProductMapper extends BaseMapper<GaoProduct, String> {
|
||||
/// 按条件查询产品
|
||||
List<GaoProduct> selectByQuery(GaoProductPage page);
|
||||
|
||||
/// 批量查询产品
|
||||
List<GaoProduct> selectByIdList(@Param("idList") Collection<String> idList);
|
||||
|
||||
/// 查询产品编码
|
||||
GaoProduct selectByStoreIdAndCode(@Param("storeId") String storeId, @Param("code") String code, @Param("excludeId") String excludeId);
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ public interface GaoSalesOrderItemMapper extends BaseMapper<GaoSalesOrderItem, S
|
||||
/// 查询订单明细
|
||||
List<GaoSalesOrderItem> selectBySalesOrderId(@Param("salesOrderId") String salesOrderId);
|
||||
|
||||
/// 批量查询订单明细
|
||||
List<GaoSalesOrderItem> selectBySalesOrderIdList(@Param("salesOrderIdList") List<String> salesOrderIdList);
|
||||
|
||||
/// 锁定订单明细
|
||||
GaoSalesOrderItem selectForUpdate(@Param("id") String id);
|
||||
|
||||
|
||||
@@ -37,4 +37,7 @@ public interface GaoSalesOrderMapper extends BaseMapper<GaoSalesOrder, String> {
|
||||
|
||||
/// 更新订单履约状态
|
||||
int updateStatus(@Param("id") String id, @Param("status") GaoSalesOrder.Status status);
|
||||
|
||||
/// 更新订单备注
|
||||
int updateRemark(@Param("id") String id, @Param("remark") String remark);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.imyeyu.api.modules.gao.entity.GaoPointRule;
|
||||
import com.imyeyu.api.modules.gao.service.GaoCustomerConsumptionRecordService;
|
||||
import com.imyeyu.api.modules.gao.service.GaoEventRecordService;
|
||||
import com.imyeyu.java.bean.timi.TimiException;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
@@ -28,11 +29,18 @@ public class GaoPointScriptContext {
|
||||
private final GaoCustomerConsumptionRecordService consumptionService;
|
||||
private final GaoEventRecordService eventRecordService;
|
||||
private final GaoPointRule rule;
|
||||
|
||||
@Getter
|
||||
private final String storeId;
|
||||
@Getter
|
||||
private final String customerId;
|
||||
@Getter
|
||||
private final String triggerSourceType;
|
||||
@Getter
|
||||
private final String triggerRefType;
|
||||
@Getter
|
||||
private final String triggerRefId;
|
||||
@Getter
|
||||
private final long occurredAt;
|
||||
|
||||
/// 参与过金额计算的消费事实,ID 到金额摘要
|
||||
@@ -51,36 +59,6 @@ public class GaoPointScriptContext {
|
||||
this.occurredAt = occurredAt;
|
||||
}
|
||||
|
||||
/// 触发来源门店 ID
|
||||
public String getStoreId() {
|
||||
return storeId;
|
||||
}
|
||||
|
||||
/// 触发来源客户 ID
|
||||
public String getCustomerId() {
|
||||
return customerId;
|
||||
}
|
||||
|
||||
/// 直接触发来源类型
|
||||
public String getTriggerSourceType() {
|
||||
return triggerSourceType;
|
||||
}
|
||||
|
||||
/// 触发对象筛选类型
|
||||
public String getTriggerRefType() {
|
||||
return triggerRefType;
|
||||
}
|
||||
|
||||
/// 触发对象筛选 ID
|
||||
public String getTriggerRefId() {
|
||||
return triggerRefId;
|
||||
}
|
||||
|
||||
/// 触发发生时间,毫秒
|
||||
public long getOccurredAt() {
|
||||
return occurredAt;
|
||||
}
|
||||
|
||||
/// 查询触发时间往前滚动一年的有效消费金额,窗口按 Asia/Shanghai 自然日对齐
|
||||
///
|
||||
/// @return 窗口内 ACTIVE 消费事实金额合计,单位分
|
||||
|
||||
@@ -16,6 +16,9 @@ public interface GaoFundRecordService extends BaseService<GaoFundRecord, String>
|
||||
/// 按条件查询资金流水
|
||||
PageResult<GaoFundRecord> pageByQuery(GaoFundRecordPage page);
|
||||
|
||||
/// 查询资金流水详情
|
||||
GaoFundRecord detail(String id);
|
||||
|
||||
/// 按销售订单查询资金流水
|
||||
List<GaoFundRecord> listByBizId(String salesOrderId);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.imyeyu.api.modules.gao.vo.GaoProductUnitSelection;
|
||||
import com.imyeyu.spring.bean.PageResult;
|
||||
import com.imyeyu.spring.service.BaseService;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/// GAO 产品服务
|
||||
@@ -21,6 +22,9 @@ public interface GaoProductService extends BaseService<GaoProduct, String> {
|
||||
/// 查询产品详情单位
|
||||
GaoProduct detail(String id);
|
||||
|
||||
/// 批量查询产品详情
|
||||
List<GaoProduct> listByIdList(Collection<String> idList);
|
||||
|
||||
/// 查询启用且允许销售的产品单位
|
||||
List<GaoProduct> listSellable(GaoProductPage page);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.imyeyu.api.modules.gao.vo.GaoDirectProductOrderCreateRequest;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoPackageOrderCreateData;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoSalesOrderCancelRequest;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoSalesOrderPage;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoSalesOrderUpdateRequest;
|
||||
import com.imyeyu.spring.bean.PageResult;
|
||||
import com.imyeyu.spring.service.BaseService;
|
||||
|
||||
@@ -27,6 +28,9 @@ public interface GaoSalesOrderService extends BaseService<GaoSalesOrder, String>
|
||||
/// 创建直接产品订单
|
||||
GaoSalesOrder createDirectProductOrder(GaoDirectProductOrderCreateRequest request);
|
||||
|
||||
/// 只更新订单备注和附件
|
||||
GaoSalesOrder updateRemarkAndAttachments(GaoSalesOrderUpdateRequest request);
|
||||
|
||||
/// 按门店和幂等号查询订单
|
||||
///
|
||||
/// @param storeId 门店 ID
|
||||
|
||||
+10
@@ -75,6 +75,16 @@ public class GaoFundRecordServiceImplement extends AbstractEntityService<GaoFund
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GaoFundRecord detail(String id) {
|
||||
TimiException.required(id, "not found fund record id");
|
||||
GaoFundRecord result = mapper.selectWithSalesOrderSummary(id);
|
||||
TimiException.required(result, "not found fund record");
|
||||
GaoFundRecord revoke = mapper.selectRevokeBySourceRecordId(result.getId());
|
||||
result.setRevokeRecordId(revoke == null ? null : revoke.getId());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GaoFundRecord> listByBizId(String salesOrderId) {
|
||||
TimiException.required(salesOrderId, "not found salesOrderId");
|
||||
|
||||
+49
-3
@@ -126,7 +126,9 @@ public class GaoOrderFulfillmentServiceImplement extends AbstractEntityService<G
|
||||
GaoOrderFulfillment fulfillment = mapper.selectById(id);
|
||||
TimiException.required(fulfillment, "not found fulfillment");
|
||||
storeScopeService.checkStoreId(fulfillment.getStoreId());
|
||||
fulfillment.setItemList(itemMapper.selectByFulfillmentId(fulfillment.getId()));
|
||||
List<GaoOrderFulfillmentItem> itemList = itemMapper.selectByFulfillmentId(fulfillment.getId());
|
||||
fillItemAttachments(itemList);
|
||||
fulfillment.setItemList(itemList);
|
||||
fulfillment.setStockRecordList(stockRecordService.listByBiz(GaoProductStockRecord.BizType.ORDER_FULFILLMENT, fulfillment.getId()));
|
||||
return fulfillment;
|
||||
}
|
||||
@@ -659,8 +661,52 @@ public class GaoOrderFulfillmentServiceImplement extends AbstractEntityService<G
|
||||
}
|
||||
|
||||
private void fillItemList(List<GaoOrderFulfillment> list) {
|
||||
for (GaoOrderFulfillment fulfillment : TimiJava.safeIterable(list)) {
|
||||
fulfillment.setItemList(itemMapper.selectByFulfillmentId(fulfillment.getId()));
|
||||
if (list == null || list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<String> fulfillmentIdList = list.stream()
|
||||
.map(GaoOrderFulfillment::getId)
|
||||
.filter(value -> value != null && !value.isBlank())
|
||||
.distinct()
|
||||
.toList();
|
||||
if (fulfillmentIdList.isEmpty()) {
|
||||
for (GaoOrderFulfillment fulfillment : list) {
|
||||
fulfillment.setItemList(List.of());
|
||||
}
|
||||
return;
|
||||
}
|
||||
Map<String, List<GaoOrderFulfillmentItem>> itemMap = new HashMap<>();
|
||||
List<GaoOrderFulfillmentItem> queriedItemList = itemMapper.selectByFulfillmentIdList(fulfillmentIdList);
|
||||
for (GaoOrderFulfillmentItem item : queriedItemList) {
|
||||
itemMap.computeIfAbsent(item.getFulfillmentId(), key -> new ArrayList<>()).add(item);
|
||||
}
|
||||
List<GaoOrderFulfillmentItem> itemList = new ArrayList<>();
|
||||
for (GaoOrderFulfillment fulfillment : list) {
|
||||
List<GaoOrderFulfillmentItem> fulfillmentItemList = itemMap.getOrDefault(fulfillment.getId(), List.of());
|
||||
fulfillment.setItemList(fulfillmentItemList);
|
||||
itemList.addAll(fulfillmentItemList);
|
||||
}
|
||||
fillItemAttachments(itemList);
|
||||
}
|
||||
|
||||
private void fillItemAttachments(List<GaoOrderFulfillmentItem> itemList) {
|
||||
if (itemList == null || itemList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<String> productIdList = itemList.stream()
|
||||
.map(GaoOrderFulfillmentItem::getProductId)
|
||||
.filter(value -> value != null && !value.isBlank())
|
||||
.distinct()
|
||||
.toList();
|
||||
if (productIdList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Map<String, List<Attachment>> attachmentMap = attachmentService.mapByBizIdList(
|
||||
Attachment.BizType.GAO_PRODUCT,
|
||||
productIdList,
|
||||
GaoProduct.AttachType.PHOTO.name());
|
||||
for (GaoOrderFulfillmentItem item : itemList) {
|
||||
item.setAttachmentList(attachmentMap.getOrDefault(item.getProductId(), List.of()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -256,6 +256,7 @@ public class GaoOrderPaymentServiceImplement implements GaoOrderPaymentService {
|
||||
record.setBizId(order.getId());
|
||||
record.setOperationType(operationType);
|
||||
record.setAmount(amount);
|
||||
record.setSalesOrderUnpaidAmountSnapshot(safe(order.getSaleAmount()) - safe(order.getPaidAmount()));
|
||||
record.setRequestNo(requestNo);
|
||||
record.setOperatorUserId(userLoginService.getRequireLoginUserId());
|
||||
record.setOccurredAt(TimiJava.defaultIfNull(occurredAt, Time.now()));
|
||||
|
||||
+11
@@ -29,6 +29,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -75,6 +76,16 @@ public class GaoProductServiceImplement extends AbstractEntityService<GaoProduct
|
||||
return product;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GaoProduct> listByIdList(Collection<String> idList) {
|
||||
if (idList == null || idList.isEmpty()) {
|
||||
return List.of();
|
||||
}
|
||||
List<GaoProduct> list = mapper.selectByIdList(idList);
|
||||
fillTransient(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GaoProduct> listSellable(GaoProductPage page) {
|
||||
TimiException.required(page, "not found product page");
|
||||
|
||||
+87
-2
@@ -34,6 +34,7 @@ import com.imyeyu.api.modules.gao.vo.GaoProductUnitSelection;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoSalesOrderCancelRequest;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoSalesOrderItemRequest;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoSalesOrderPage;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoSalesOrderUpdateRequest;
|
||||
import com.imyeyu.api.modules.system.entity.Logger;
|
||||
import com.imyeyu.api.modules.system.service.LoggerService;
|
||||
import com.imyeyu.api.modules.user.service.PermissionChecker;
|
||||
@@ -55,8 +56,10 @@ import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -100,6 +103,7 @@ public class GaoSalesOrderServiceImplement extends AbstractEntityService<GaoSale
|
||||
result.setTotal(mapper.countByQuery(page));
|
||||
List<GaoSalesOrder> list = mapper.selectByQuery(page);
|
||||
fillItemList(list);
|
||||
fillCustomer(list);
|
||||
result.setList(list);
|
||||
return result;
|
||||
}
|
||||
@@ -109,7 +113,11 @@ public class GaoSalesOrderServiceImplement extends AbstractEntityService<GaoSale
|
||||
GaoSalesOrder order = get(id);
|
||||
TimiException.required(order, "not found sales order");
|
||||
storeScopeService.checkStoreId(order.getStoreId());
|
||||
order.setItemList(itemMapper.selectBySalesOrderId(order.getId()));
|
||||
List<GaoSalesOrderItem> itemList = itemMapper.selectBySalesOrderId(order.getId());
|
||||
fillItemAttachments(itemList);
|
||||
order.setItemList(itemList);
|
||||
fillCustomer(List.of(order));
|
||||
order.setAttachmentList(attachmentService.listByBizId(Attachment.BizType.GAO_SALES_ORDER, order.getId()));
|
||||
order.setFundRecordList(fundRecordService.listByBizId(order.getId()));
|
||||
if (order.getSourceEventRecordId() != null) {
|
||||
order.setSourceEventRecord(eventRecordService.get(order.getSourceEventRecordId()));
|
||||
@@ -132,6 +140,19 @@ public class GaoSalesOrderServiceImplement extends AbstractEntityService<GaoSale
|
||||
return loggerService.execute(Logger.Module.GAO, "GAO_SALES_ORDER_DIRECT_PRODUCT_CREATE", request, () -> createDirectInternal(request));
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public GaoSalesOrder updateRemarkAndAttachments(GaoSalesOrderUpdateRequest request) {
|
||||
return loggerService.execute(Logger.Module.GAO, "GAO_SALES_ORDER_UPDATE", request, () -> {
|
||||
TimiException.required(request, "not found sales order update request");
|
||||
TimiException.required(request.getId(), "not found sales order.id");
|
||||
GaoSalesOrder order = getForUpdate(request.getId());
|
||||
TimiException.requiredTrue(1 == mapper.updateRemark(order.getId(), request.getRemark()), "订单备注更新失败");
|
||||
attachmentService.updateByBizId(Attachment.BizType.GAO_SALES_ORDER, order.getId(), request.getAttachmentList());
|
||||
return detail(order.getId());
|
||||
});
|
||||
}
|
||||
|
||||
private GaoSalesOrder createDirectInternal(GaoDirectProductOrderCreateRequest request) {
|
||||
TimiException.required(request, "not found direct product order request");
|
||||
String requestNo = requiredText(request.getRequestNo(), "not found requestNo");
|
||||
@@ -436,10 +457,74 @@ public class GaoSalesOrderServiceImplement extends AbstractEntityService<GaoSale
|
||||
}
|
||||
|
||||
private void fillItemList(List<GaoSalesOrder> orderList) {
|
||||
if (orderList == null || orderList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<String> orderIdList = orderList.stream()
|
||||
.map(GaoSalesOrder::getId)
|
||||
.filter(value -> value != null && !value.isBlank())
|
||||
.distinct()
|
||||
.toList();
|
||||
Map<String, List<GaoSalesOrderItem>> itemMap = new HashMap<>();
|
||||
if (!orderIdList.isEmpty()) {
|
||||
List<GaoSalesOrderItem> queriedItemList = itemMapper.selectBySalesOrderIdList(orderIdList);
|
||||
for (GaoSalesOrderItem item : TimiJava.safeIterable(queriedItemList)) {
|
||||
itemMap.computeIfAbsent(item.getSalesOrderId(), key -> new ArrayList<>()).add(item);
|
||||
}
|
||||
}
|
||||
List<GaoSalesOrderItem> itemList = new ArrayList<>();
|
||||
for (GaoSalesOrder order : TimiJava.safeIterable(orderList)) {
|
||||
order.setItemList(itemMapper.selectBySalesOrderId(order.getId()));
|
||||
List<GaoSalesOrderItem> orderItemList = itemMap.getOrDefault(order.getId(), List.of());
|
||||
order.setItemList(orderItemList);
|
||||
itemList.addAll(orderItemList);
|
||||
order.setUnpaidAmount(safe(order.getSaleAmount()) - safe(order.getPaidAmount()));
|
||||
}
|
||||
fillItemAttachments(itemList);
|
||||
}
|
||||
|
||||
private void fillItemAttachments(List<GaoSalesOrderItem> itemList) {
|
||||
if (itemList == null || itemList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<String> productIdList = itemList.stream()
|
||||
.map(GaoSalesOrderItem::getProductId)
|
||||
.filter(value -> value != null && !value.isBlank())
|
||||
.distinct()
|
||||
.toList();
|
||||
if (productIdList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Map<String, List<Attachment>> attachmentMap = attachmentService.mapByBizIdList(
|
||||
Attachment.BizType.GAO_PRODUCT,
|
||||
productIdList,
|
||||
GaoProduct.AttachType.PHOTO.name());
|
||||
for (GaoSalesOrderItem item : itemList) {
|
||||
item.setAttachmentList(attachmentMap.getOrDefault(item.getProductId(), List.of()));
|
||||
}
|
||||
}
|
||||
|
||||
private void fillCustomer(List<GaoSalesOrder> orderList) {
|
||||
Set<String> customerIdSet = new HashSet<>();
|
||||
for (GaoSalesOrder order : TimiJava.safeIterable(orderList)) {
|
||||
if (TimiJava.isNotEmpty(order.getCustomerId())) {
|
||||
customerIdSet.add(order.getCustomerId());
|
||||
}
|
||||
}
|
||||
if (customerIdSet.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> customerIdList = new ArrayList<>(customerIdSet);
|
||||
Map<String, GaoCustomer> customerMap = customerService.mapByIdList(customerIdList);
|
||||
Map<String, List<Attachment>> attachmentMap = attachmentService.mapByBizIdList(Attachment.BizType.GAO_CUSTOMER, customerIdList);
|
||||
for (GaoSalesOrder order : TimiJava.safeIterable(orderList)) {
|
||||
GaoCustomer customer = customerMap.get(order.getCustomerId());
|
||||
if (customer == null) {
|
||||
continue;
|
||||
}
|
||||
customer.setAttachmentList(attachmentMap.getOrDefault(customer.getId(), List.of()));
|
||||
order.setCustomer(customer);
|
||||
}
|
||||
}
|
||||
|
||||
private BigDecimal validateQuantity(GaoProduct product, BigDecimal quantity) {
|
||||
|
||||
@@ -31,6 +31,18 @@ public class GaoProductStockRecordPage extends BasePage {
|
||||
/// 操作类型
|
||||
private GaoProductStockRecord.OperationType operationType;
|
||||
|
||||
/// 仅查询仍然生效的履约预占流水
|
||||
private Boolean activeReservationOnly;
|
||||
|
||||
/// 库存变动方向,IN 为入库,OUT 为出库
|
||||
public enum Direction {
|
||||
IN,
|
||||
OUT
|
||||
}
|
||||
|
||||
/// 库存变动方向
|
||||
private Direction direction;
|
||||
|
||||
/// 起始发生时间
|
||||
private Long beginAt;
|
||||
|
||||
|
||||
@@ -28,6 +28,12 @@ public class GaoSalesOrderPage extends BasePage {
|
||||
/// 付款状态
|
||||
private GaoSalesOrder.PaymentStatus paymentStatus;
|
||||
|
||||
/// 退款状态
|
||||
private GaoSalesOrder.RefundStatus refundStatus;
|
||||
|
||||
/// true 为筛选可收款且未付清订单
|
||||
private Boolean pendingReceive;
|
||||
|
||||
/// true 为筛选已履约但未付清订单
|
||||
private Boolean fulfilledButUnpaid;
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.imyeyu.api.modules.gao.vo;
|
||||
|
||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/// GAO 销售订单备注和附件修改请求
|
||||
///
|
||||
/// 该请求只允许修改备注和订单附件,不承载订单其他字段。
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-09-05
|
||||
@Data
|
||||
public class GaoSalesOrderUpdateRequest {
|
||||
|
||||
/// 订单 ID
|
||||
private String id;
|
||||
|
||||
/// 订单附件
|
||||
private List<Attachment> attachmentList;
|
||||
|
||||
/// 备注
|
||||
private String remark;
|
||||
}
|
||||
@@ -49,10 +49,10 @@ public class RoleController {
|
||||
@RequireCorePermission(CorePermissionCode.ROLE_READ)
|
||||
@PostMapping("/list")
|
||||
public PageResult<Role> list(@RequestBody Page<Role> page) {
|
||||
Set<String> manageableRoleIdSet = listManageableRoleId();
|
||||
Set<String> visibleRoleIdSet = listVisibleRoleId();
|
||||
PageResult<Role> result = service.page(page);
|
||||
if (result.getList() != null) {
|
||||
result.setList(result.getList().stream().filter(role -> manageableRoleIdSet.contains(role.getId())).toList());
|
||||
result.setList(result.getList().stream().filter(role -> visibleRoleIdSet.contains(role.getId())).toList());
|
||||
result.getList().forEach(this::fillRoleDetail);
|
||||
}
|
||||
return result;
|
||||
@@ -83,7 +83,7 @@ public class RoleController {
|
||||
@PostMapping("/detail")
|
||||
public Role detail(@RequestParam String id) {
|
||||
Role role = service.get(id);
|
||||
requireManageableRole(role.getId());
|
||||
requireVisibleRole(role.getId());
|
||||
fillRoleDetail(role);
|
||||
return role;
|
||||
}
|
||||
@@ -105,7 +105,7 @@ public class RoleController {
|
||||
@RequireCorePermission(CorePermissionCode.ROLE_PERMISSION_READ)
|
||||
@PostMapping("/permission/grantable/list")
|
||||
public List<Permission> listGrantableRolePermission(@RequestParam String roleId) {
|
||||
requireManageableRole(roleId);
|
||||
requireVisibleRole(roleId);
|
||||
return service.listGrantableRolePermission(roleId);
|
||||
}
|
||||
|
||||
@@ -137,6 +137,12 @@ public class RoleController {
|
||||
return service.listGrantableParentRole(roleId);
|
||||
}
|
||||
|
||||
@RequireCorePermission(CorePermissionCode.ROLE_CREATE)
|
||||
@PostMapping("/parent/create/grantable/list")
|
||||
public List<Role> listCreateGrantableParentRole(@RequestParam ModuleCode moduleCode) {
|
||||
return service.listCreateGrantableParentRole(moduleCode);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequireCorePermission(CorePermissionCode.ROLE_UPDATE)
|
||||
@PostMapping("/parent/update")
|
||||
@@ -197,6 +203,19 @@ public class RoleController {
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private Set<String> listVisibleRoleId() {
|
||||
Set<String> roleIdSet = listManageableRoleId();
|
||||
String loginUserId = userLoginService.getRequireLoginUserId();
|
||||
roleIdSet.addAll(userRoleService.listRoleByUserId(loginUserId).stream().map(Role::getId).toList());
|
||||
return roleIdSet;
|
||||
}
|
||||
|
||||
private void requireVisibleRole(String roleId) {
|
||||
if (!listVisibleRoleId().contains(roleId)) {
|
||||
throw new TimiException(TimiCode.PERMISSION_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
private void requireManageableRole(String roleId) {
|
||||
if (!listManageableRoleId().contains(roleId)) {
|
||||
throw new TimiException(TimiCode.PERMISSION_ERROR);
|
||||
|
||||
@@ -75,6 +75,12 @@ public interface RoleService extends BaseService<Role, String> {
|
||||
/// @return 角色列表
|
||||
List<Role> listGrantableParentRole(String roleId);
|
||||
|
||||
/// 查询创建模块角色时可选的管理父级角色
|
||||
///
|
||||
/// @param moduleCode 目标模块代码
|
||||
/// @return 角色列表
|
||||
List<Role> listCreateGrantableParentRole(ModuleCode moduleCode);
|
||||
|
||||
/// 修改角色管理父级
|
||||
///
|
||||
/// @param role 角色
|
||||
|
||||
+14
-2
@@ -83,11 +83,12 @@ public class AuthorizationBoundaryServiceImplement implements AuthorizationBound
|
||||
@Override
|
||||
public void checkCanCreateRole(String operatorUserId, Role role) {
|
||||
checkCorePermission(operatorUserId, CorePermissionCode.ROLE_CREATE);
|
||||
TimiException.required(role.getModuleCode(), "not found role.moduleCode");
|
||||
TimiException.required(role.getOwnerType(), "not found role.ownerType");
|
||||
checkOwnerDefinition(role.getModuleCode(), role.getOwnerType(), role.getOwnerId());
|
||||
if (authorizationScopeService.isSystemAdmin(operatorUserId)) {
|
||||
return;
|
||||
}
|
||||
TimiException.required(role.getModuleCode(), "not found role.moduleCode");
|
||||
TimiException.required(role.getOwnerType(), "not found role.ownerType");
|
||||
TimiException.requiredTrue(!Boolean.TRUE.equals(role.getBuiltin()), "不能创建内置角色");
|
||||
TimiException.requiredTrue(!Boolean.TRUE.equals(role.getProtectedRole()), "不能创建受保护角色");
|
||||
checkOwnerScope(operatorUserId, role.getModuleCode(), role.getOwnerType(), role.getOwnerId());
|
||||
@@ -98,6 +99,11 @@ public class AuthorizationBoundaryServiceImplement implements AuthorizationBound
|
||||
checkCorePermission(operatorUserId, CorePermissionCode.ROLE_UPDATE);
|
||||
Role dbRole = roleMapper.selectById(role.getId());
|
||||
TimiException.required(dbRole, "not found role");
|
||||
if (role.getOwnerType() != null || role.getOwnerId() != null) {
|
||||
AuthOwnerType ownerType = TimiJava.defaultIfNull(role.getOwnerType(), dbRole.getOwnerType());
|
||||
String ownerId = TimiJava.defaultIfEmpty(role.getOwnerId(), dbRole.getOwnerId());
|
||||
checkOwnerDefinition(dbRole.getModuleCode(), ownerType, ownerId);
|
||||
}
|
||||
if (authorizationScopeService.isSystemAdmin(operatorUserId)) {
|
||||
return;
|
||||
}
|
||||
@@ -339,6 +345,12 @@ public class AuthorizationBoundaryServiceImplement implements AuthorizationBound
|
||||
TimiException.requiredTrue(resolver == null || resolver.canUseOwnerScope(operatorUserId, ownerType, ownerId), "归属范围不在可管理范围内");
|
||||
}
|
||||
|
||||
private void checkOwnerDefinition(ModuleCode moduleCode, AuthOwnerType ownerType, String ownerId) {
|
||||
if (ownerType == AuthOwnerType.MODULE) {
|
||||
TimiException.requiredTrue(moduleCode.name().equals(ownerId), "模块级归属 ID 必须等于模块代码");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCorePermission(String operatorUserId, CorePermissionCode permissionCode) {
|
||||
TimiException.requiredTrue(hasPermission(operatorUserId, ModuleCode.CORE, permissionCode.getValue()), "权限不足:%s".formatted(permissionCode.getValue()));
|
||||
}
|
||||
|
||||
@@ -355,6 +355,25 @@ public class RoleServiceImplement extends AbstractEntityService<Role, String> im
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Role> listCreateGrantableParentRole(ModuleCode moduleCode) {
|
||||
String loginUserId = userLoginService.getRequireLoginUserId();
|
||||
if (authorizationScopeService.isSystemAdmin(loginUserId)) {
|
||||
return mapper.selectAll();
|
||||
}
|
||||
Set<String> directOperatorRoleIdSet = userRoleMapper.selectByUserIdList(List.of(loginUserId))
|
||||
.stream()
|
||||
.map(UserRole::getRoleId)
|
||||
.collect(Collectors.toSet());
|
||||
if (TimiJava.isEmpty(directOperatorRoleIdSet)) {
|
||||
return List.of();
|
||||
}
|
||||
return mapper.selectByIdList(directOperatorRoleIdSet)
|
||||
.stream()
|
||||
.filter(role -> role.getModuleCode() == moduleCode)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void updateRoleParent(Role role) {
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
ALTER TABLE `gao_point_ledger`
|
||||
ADD COLUMN `sales_order_id` VARCHAR(36) NULL COMMENT '关联销售订单 ID' AFTER `trigger_source_id`,
|
||||
ADD KEY `idx_gao_point_ledger_sales_order` (`sales_order_id`);
|
||||
ADD COLUMN IF NOT EXISTS `sales_order_id` VARCHAR(36) NULL COMMENT '关联销售订单 ID' AFTER `trigger_source_id`,
|
||||
ADD KEY IF NOT EXISTS `idx_gao_point_ledger_sales_order` (`sales_order_id`);
|
||||
|
||||
-- 将旧规则 sourceEventId 指向的登记事件标记为退役消费事件
|
||||
UPDATE `gao_event` e
|
||||
@@ -41,4 +41,4 @@ WHERE e.`biz_type` = 'LEGACY_CONSUMPTION'
|
||||
AND r.`number_value` IS NOT NULL
|
||||
AND r.`number_value` > 0
|
||||
AND r.`deleted_at` IS NULL
|
||||
ON DUPLICATE KEY UPDATE `id` = `id`;
|
||||
ON DUPLICATE KEY UPDATE `id` = `gao_customer_consumption_record`.`id`;
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `gao_fund_record`
|
||||
ADD COLUMN IF NOT EXISTS `sales_order_unpaid_amount_snapshot` BIGINT NULL COMMENT '流水发生时销售订单剩余待收款金额快照,单位分' AFTER `amount`;
|
||||
@@ -26,8 +26,9 @@
|
||||
<select id="selectByQuery" resultType="com.imyeyu.api.modules.gao.entity.GaoCustomerPackage">
|
||||
SELECT p.* FROM `gao_customer_package` p
|
||||
LEFT JOIN `gao_customer` c ON c.`id` = p.`customer_id`
|
||||
LEFT JOIN `gao_sales_order` o ON o.`id` = p.`sales_order_id` AND o.`store_id` = p.`store_id` AND o.`deleted_at` IS NULL
|
||||
WHERE <include refid="queryWhere"/>
|
||||
ORDER BY p.`purchased_at` DESC, p.`created_at` DESC
|
||||
ORDER BY o.`purchased_at` DESC, p.`created_at` DESC
|
||||
LIMIT #{offset}, #{limit}
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
@@ -11,6 +11,13 @@
|
||||
WHERE `id` = #{id} AND `deleted_at` IS NULL
|
||||
FOR UPDATE
|
||||
</select>
|
||||
<select id="selectWithSalesOrderSummary" resultType="com.imyeyu.api.modules.gao.entity.GaoFundRecord">
|
||||
SELECT f.*, o.`sale_amount` AS `sales_order_amount`
|
||||
FROM `gao_fund_record` f
|
||||
LEFT JOIN `gao_sales_order` o ON o.`id` = f.`biz_id` AND o.`store_id` = f.`store_id` AND o.`deleted_at` IS NULL
|
||||
WHERE f.`id` = #{id} AND f.`deleted_at` IS NULL
|
||||
LIMIT 1
|
||||
</select>
|
||||
<select id="selectRevokeBySourceRecordId" resultType="com.imyeyu.api.modules.gao.entity.GaoFundRecord">
|
||||
SELECT * FROM `gao_fund_record`
|
||||
WHERE `source_record_id` = #{sourceRecordId} AND `deleted_at` IS NULL
|
||||
@@ -21,9 +28,18 @@
|
||||
WHERE `biz_id` = #{bizId} AND `operation_type` = 'RECEIVE' AND `status` = 'PENDING' AND `deleted_at` IS NULL
|
||||
</select>
|
||||
<select id="selectByBizId" resultType="com.imyeyu.api.modules.gao.entity.GaoFundRecord">
|
||||
SELECT * FROM `gao_fund_record`
|
||||
WHERE `biz_id` = #{bizId} AND `deleted_at` IS NULL
|
||||
ORDER BY `occurred_at` DESC, `created_at` DESC
|
||||
SELECT f.*,
|
||||
o.`sale_amount` AS `sales_order_amount`,
|
||||
(
|
||||
SELECT r.`id`
|
||||
FROM `gao_fund_record` r
|
||||
WHERE r.`source_record_id` = f.`id` AND r.`deleted_at` IS NULL
|
||||
LIMIT 1
|
||||
) AS `revoke_record_id`
|
||||
FROM `gao_fund_record` f
|
||||
LEFT JOIN `gao_sales_order` o ON o.`id` = f.`biz_id` AND o.`store_id` = f.`store_id` AND o.`deleted_at` IS NULL
|
||||
WHERE f.`biz_id` = #{bizId} AND f.`deleted_at` IS NULL
|
||||
ORDER BY f.`occurred_at` DESC, f.`created_at` DESC
|
||||
</select>
|
||||
<sql id="queryWhere">
|
||||
f.`deleted_at` IS NULL
|
||||
@@ -41,7 +57,16 @@
|
||||
SELECT COUNT(1) FROM `gao_fund_record` f WHERE <include refid="queryWhere"/>
|
||||
</select>
|
||||
<select id="selectByQuery" resultType="com.imyeyu.api.modules.gao.entity.GaoFundRecord">
|
||||
SELECT f.* FROM `gao_fund_record` f WHERE <include refid="queryWhere"/>
|
||||
SELECT f.*, o.`sale_amount` AS `sales_order_amount`,
|
||||
(
|
||||
SELECT r.`id`
|
||||
FROM `gao_fund_record` r
|
||||
WHERE r.`source_record_id` = f.`id` AND r.`deleted_at` IS NULL
|
||||
LIMIT 1
|
||||
) AS `revoke_record_id`
|
||||
FROM `gao_fund_record` f
|
||||
LEFT JOIN `gao_sales_order` o ON o.`id` = f.`biz_id` AND o.`store_id` = f.`store_id` AND o.`deleted_at` IS NULL
|
||||
WHERE <include refid="queryWhere"/>
|
||||
ORDER BY f.`occurred_at` DESC, f.`created_at` DESC
|
||||
LIMIT #{offset}, #{limit}
|
||||
</select>
|
||||
|
||||
@@ -6,6 +6,14 @@
|
||||
WHERE `fulfillment_id` = #{fulfillmentId}
|
||||
ORDER BY `created_at`
|
||||
</select>
|
||||
<select id="selectByFulfillmentIdList" resultType="com.imyeyu.api.modules.gao.entity.GaoOrderFulfillmentItem">
|
||||
SELECT * FROM `gao_order_fulfillment_item`
|
||||
WHERE `fulfillment_id` IN
|
||||
<foreach collection="fulfillmentIdList" item="fulfillmentId" separator="," open="(" close=")">
|
||||
#{fulfillmentId}
|
||||
</foreach>
|
||||
ORDER BY `created_at`
|
||||
</select>
|
||||
<select id="selectByFulfillmentIdForUpdate" resultType="com.imyeyu.api.modules.gao.entity.GaoOrderFulfillmentItem">
|
||||
SELECT * FROM `gao_order_fulfillment_item`
|
||||
WHERE `fulfillment_id` = #{fulfillmentId}
|
||||
|
||||
@@ -31,6 +31,16 @@
|
||||
ORDER BY `sort`, `name`, `code`, `created_at` DESC
|
||||
LIMIT #{offset}, #{limit}
|
||||
</select>
|
||||
<select id="selectByIdList" resultType="com.imyeyu.api.modules.gao.entity.GaoProduct">
|
||||
SELECT * FROM `gao_product`
|
||||
WHERE `deleted_at` IS NULL
|
||||
<choose>
|
||||
<when test="idList != null and !idList.isEmpty()">
|
||||
AND `id` IN <foreach collection="idList" item="id" open="(" separator="," close=")">#{id}</foreach>
|
||||
</when>
|
||||
<otherwise>AND FALSE</otherwise>
|
||||
</choose>
|
||||
</select>
|
||||
<select id="selectByStoreIdAndCode" resultType="com.imyeyu.api.modules.gao.entity.GaoProduct">
|
||||
SELECT * FROM `gao_product`
|
||||
WHERE `store_id` = #{storeId} AND `code` = #{code} AND `deleted_at` IS NULL
|
||||
|
||||
@@ -12,20 +12,37 @@
|
||||
</select>
|
||||
<select id="countByQuery" resultType="long">
|
||||
SELECT COUNT(1)
|
||||
FROM `gao_product_stock` s
|
||||
INNER JOIN `gao_product` p ON p.`id` = s.`product_id` AND p.`deleted_at` IS NULL
|
||||
WHERE 1 = 1
|
||||
<if test="storeId != null and storeId != ''">AND s.`store_id` = #{storeId}</if>
|
||||
<if test="productId != null and productId != ''">AND s.`product_id` = #{productId}</if>
|
||||
FROM `gao_product` p
|
||||
LEFT JOIN `gao_product_stock` s ON s.`product_id` = p.`id`
|
||||
<choose>
|
||||
<when test="storeId != null and storeId != ''">AND s.`store_id` = #{storeId}</when>
|
||||
<otherwise>AND s.`store_id` = p.`store_id`</otherwise>
|
||||
</choose>
|
||||
WHERE p.`deleted_at` IS NULL
|
||||
AND p.`stock_enabled` = 1
|
||||
<if test="storeId != null and storeId != ''">AND p.`store_id` = #{storeId}</if>
|
||||
<if test="productId != null and productId != ''">AND p.`id` = #{productId}</if>
|
||||
<if test="keyword != null and keyword.trim() != ''">AND (p.`code` LIKE CONCAT('%', #{keyword}, '%') OR p.`name` LIKE CONCAT('%', #{keyword}, '%'))</if>
|
||||
</select>
|
||||
<select id="selectByQuery" resultType="com.imyeyu.api.modules.gao.entity.GaoProductStock">
|
||||
SELECT s.*
|
||||
FROM `gao_product_stock` s
|
||||
INNER JOIN `gao_product` p ON p.`id` = s.`product_id` AND p.`deleted_at` IS NULL
|
||||
WHERE 1 = 1
|
||||
<if test="storeId != null and storeId != ''">AND s.`store_id` = #{storeId}</if>
|
||||
<if test="productId != null and productId != ''">AND s.`product_id` = #{productId}</if>
|
||||
SELECT s.`id`,
|
||||
p.`store_id`,
|
||||
p.`id` AS `product_id`,
|
||||
COALESCE(s.`on_hand_quantity`, 0) AS `on_hand_quantity`,
|
||||
COALESCE(s.`reserved_quantity`, 0) AS `reserved_quantity`,
|
||||
s.`updated_by`,
|
||||
s.`created_at`,
|
||||
s.`updated_at`
|
||||
FROM `gao_product` p
|
||||
LEFT JOIN `gao_product_stock` s ON s.`product_id` = p.`id`
|
||||
<choose>
|
||||
<when test="storeId != null and storeId != ''">AND s.`store_id` = #{storeId}</when>
|
||||
<otherwise>AND s.`store_id` = p.`store_id`</otherwise>
|
||||
</choose>
|
||||
WHERE p.`deleted_at` IS NULL
|
||||
AND p.`stock_enabled` = 1
|
||||
<if test="storeId != null and storeId != ''">AND p.`store_id` = #{storeId}</if>
|
||||
<if test="productId != null and productId != ''">AND p.`id` = #{productId}</if>
|
||||
<if test="keyword != null and keyword.trim() != ''">AND (p.`code` LIKE CONCAT('%', #{keyword}, '%') OR p.`name` LIKE CONCAT('%', #{keyword}, '%'))</if>
|
||||
ORDER BY p.`sort`, p.`name`, p.`code`
|
||||
LIMIT #{offset}, #{limit}
|
||||
|
||||
@@ -35,6 +35,20 @@
|
||||
<if test="bizType != null">AND r.`biz_type` = #{bizType}</if>
|
||||
<if test="bizId != null and bizId != ''">AND r.`biz_id` = #{bizId}</if>
|
||||
<if test="operationType != null">AND r.`operation_type` = #{operationType}</if>
|
||||
<if test="activeReservationOnly == true">
|
||||
AND r.`operation_type` = 'ORDER_RESERVE'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM `gao_product_stock_record` c
|
||||
WHERE c.`store_id` = r.`store_id`
|
||||
AND c.`biz_type` = r.`biz_type`
|
||||
AND c.`biz_id` = r.`biz_id`
|
||||
AND c.`product_id` = r.`product_id`
|
||||
AND c.`operation_type` IN ('ORDER_RELEASE', 'ORDER_OUT')
|
||||
)
|
||||
</if>
|
||||
<if test="direction != null and direction.name() == 'IN'">AND 0 < r.`on_hand_delta`</if>
|
||||
<if test="direction != null and direction.name() == 'OUT'">AND r.`on_hand_delta` < 0</if>
|
||||
<if test="beginAt != null">AND r.`occurred_at` >= #{beginAt}</if>
|
||||
<if test="endAt != null">AND r.`occurred_at` <= #{endAt}</if>
|
||||
</sql>
|
||||
|
||||
@@ -6,6 +6,15 @@
|
||||
WHERE `sales_order_id` = #{salesOrderId} AND `deleted_at` IS NULL
|
||||
ORDER BY `sort`, `created_at`
|
||||
</select>
|
||||
<select id="selectBySalesOrderIdList" resultType="com.imyeyu.api.modules.gao.entity.GaoSalesOrderItem">
|
||||
SELECT * FROM `gao_sales_order_item`
|
||||
WHERE `sales_order_id` IN
|
||||
<foreach collection="salesOrderIdList" item="salesOrderId" separator="," open="(" close=")">
|
||||
#{salesOrderId}
|
||||
</foreach>
|
||||
AND `deleted_at` IS NULL
|
||||
ORDER BY `sales_order_id`, `sort`, `created_at`
|
||||
</select>
|
||||
<select id="selectForUpdate" resultType="com.imyeyu.api.modules.gao.entity.GaoSalesOrderItem">
|
||||
SELECT * FROM `gao_sales_order_item`
|
||||
WHERE `id` = #{id} AND `deleted_at` IS NULL
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
<if test="orderType != null">AND o.`order_type` = #{orderType}</if>
|
||||
<if test="status != null">AND o.`status` = #{status}</if>
|
||||
<if test="paymentStatus != null">AND o.`payment_status` = #{paymentStatus}</if>
|
||||
<if test="refundStatus != null">AND o.`refund_status` = #{refundStatus}</if>
|
||||
<if test="pendingReceive != null and pendingReceive">AND o.`status` IN ('ACTIVE', 'FULFILLED') AND o.`payment_status` IN ('UNPAID', 'PARTIALLY_PAID')</if>
|
||||
<if test="fulfilledButUnpaid != null and fulfilledButUnpaid">AND o.`status` = 'FULFILLED' AND o.`paid_amount` < o.`sale_amount`</if>
|
||||
<if test="keyword != null and keyword.trim() != ''">AND (o.`order_no` LIKE CONCAT('%', #{keyword}, '%') OR c.`name` LIKE CONCAT('%', #{keyword}, '%') OR c.`code` LIKE CONCAT('%', #{keyword}, '%'))</if>
|
||||
<if test="beginAt != null">AND o.`purchased_at` >= #{beginAt}</if>
|
||||
@@ -48,4 +50,9 @@
|
||||
SET `status` = #{status}, `updated_at` = FLOOR(UNIX_TIMESTAMP(NOW(3)) * 1000)
|
||||
WHERE `id` = #{id} AND `deleted_at` IS NULL
|
||||
</update>
|
||||
<update id="updateRemark">
|
||||
UPDATE `gao_sales_order`
|
||||
SET `remark` = #{remark}, `updated_at` = FLOOR(UNIX_TIMESTAMP(NOW(3)) * 1000)
|
||||
WHERE `id` = #{id} AND `deleted_at` IS NULL
|
||||
</update>
|
||||
</mapper>
|
||||
|
||||
Reference in New Issue
Block a user