v1.0.31 #43

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