add point redemption

This commit is contained in:
Timi
2026-09-15 01:25:32 +08:00
parent 8618a00e5d
commit ac310414fe
30 changed files with 1786 additions and 6 deletions
@@ -0,0 +1,77 @@
CREATE TABLE `gao_point_redeem_sku` (
`id` VARCHAR(36) NOT NULL,
`store_id` VARCHAR(36) NOT NULL COMMENT '门店 ID',
`sku_id` VARCHAR(36) NOT NULL COMMENT 'SKU ID',
`sku_unit_id` VARCHAR(36) NOT NULL COMMENT 'SKU 单位 ID',
`status` VARCHAR(32) NOT NULL COMMENT 'DRAFT 草稿,ACTIVE 启用,INACTIVE 停用,DELETED 删除',
`default_point_cost` BIGINT NOT NULL COMMENT '每个业务单位默认所需积分',
`begin_at` BIGINT NULL COMMENT '生效开始时间戳,毫秒',
`end_at` BIGINT NULL COMMENT '生效结束时间戳,毫秒',
`max_total_quantity` DECIMAL(18,3) NULL COMMENT '每客户累计最多兑换数量',
`max_daily_quantity` DECIMAL(18,3) NULL COMMENT '每客户自然日最多兑换数量',
`max_monthly_quantity` DECIMAL(18,3) NULL COMMENT '每客户自然月最多兑换数量',
`remark` TEXT NULL COMMENT '备注',
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NULL,
`deleted_at` BIGINT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_gao_point_redeem_sku_store_sku_unit` (`store_id`, `sku_id`, `sku_unit_id`),
KEY `idx_gao_point_redeem_sku_store_status_time` (`store_id`, `status`, `begin_at`, `end_at`, `created_at`),
KEY `idx_gao_point_redeem_sku_sku` (`store_id`, `sku_id`, `sku_unit_id`)
) COMMENT='GAO 积分兑换 SKU 配置';
CREATE TABLE `gao_point_redemption` (
`id` VARCHAR(36) NOT NULL,
`store_id` VARCHAR(36) NOT NULL COMMENT '门店 ID',
`customer_id` VARCHAR(36) NOT NULL COMMENT '客户 ID',
`request_no` VARCHAR(128) NOT NULL COMMENT '创建幂等号',
`redeem_sku_id_snapshot` VARCHAR(36) NOT NULL COMMENT '兑换 SKU 配置 ID 快照',
`product_id_snapshot` VARCHAR(36) NOT NULL COMMENT '产品 ID 快照',
`product_name_snapshot` VARCHAR(128) NOT NULL COMMENT '产品名称快照',
`product_type_snapshot` VARCHAR(32) NOT NULL COMMENT '产品类型快照',
`sku_id_snapshot` VARCHAR(36) NOT NULL COMMENT 'SKU ID 快照',
`sku_code_snapshot` VARCHAR(64) NOT NULL COMMENT 'SKU 编码快照',
`sku_name_snapshot` VARCHAR(128) NOT NULL COMMENT 'SKU 名称快照',
`sku_spec_snapshot` JSON NOT NULL COMMENT 'SKU 规格结构快照',
`sku_unit_id_snapshot` VARCHAR(36) NOT NULL COMMENT 'SKU 单位 ID 快照',
`unit_snapshot` VARCHAR(32) NOT NULL COMMENT '单位名称快照',
`base_quantity_per_unit_snapshot` DECIMAL(18,6) NOT NULL COMMENT '每个业务单位基础数量快照',
`allow_decimal_quantity_snapshot` TINYINT(1) NOT NULL COMMENT 'true 为允许小数数量快照',
`quantity` DECIMAL(18,3) NOT NULL COMMENT '兑换业务数量',
`base_quantity` DECIMAL(18,3) NOT NULL COMMENT '兑换基础数量',
`default_point_cost` BIGINT NOT NULL COMMENT '默认总积分',
`actual_point_cost` BIGINT NOT NULL COMMENT '实际扣除总积分',
`returned_quantity` DECIMAL(18,3) NOT NULL DEFAULT 0 COMMENT '累计已退业务数量',
`returned_point_cost` BIGINT NOT NULL DEFAULT 0 COMMENT '累计已返积分',
`status` VARCHAR(32) NOT NULL COMMENT 'COMPLETED 完成,PARTIALLY_RETURNED 部分退货,FULLY_RETURNED 全部退货',
`operator_user_id` VARCHAR(36) NOT NULL COMMENT '兑换操作人',
`redeemed_at` BIGINT NOT NULL COMMENT '兑换完成时间',
`remark` TEXT NULL COMMENT '备注',
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NULL,
`deleted_at` BIGINT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_gao_point_redemption_store_request` (`store_id`, `request_no`),
KEY `idx_gao_point_redemption_customer_status_time` (`store_id`, `customer_id`, `status`, `redeemed_at`),
KEY `idx_gao_point_redemption_sku_status_time` (`store_id`, `sku_id_snapshot`, `status`, `redeemed_at`),
KEY `idx_gao_point_redemption_config_time` (`redeem_sku_id_snapshot`, `redeemed_at`)
) COMMENT='GAO 积分兑换单';
CREATE TABLE `gao_point_redemption_return` (
`id` VARCHAR(36) NOT NULL,
`redemption_id` VARCHAR(36) NOT NULL COMMENT '兑换单 ID',
`request_no` VARCHAR(128) NOT NULL COMMENT '退货幂等号',
`quantity` DECIMAL(18,3) NOT NULL COMMENT '本次退货业务数量',
`base_quantity` DECIMAL(18,3) NOT NULL COMMENT '本次退货基础数量',
`point_cost` BIGINT NOT NULL COMMENT '本次实际返还积分',
`stock_record_id` VARCHAR(36) NULL COMMENT '实物退货入库流水 ID',
`operator_user_id` VARCHAR(36) NOT NULL COMMENT '退货操作人',
`returned_at` BIGINT NOT NULL COMMENT '退货时间',
`remark` TEXT NULL COMMENT '退货原因和备注',
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NULL,
`deleted_at` BIGINT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_gao_point_redemption_return_request` (`redemption_id`, `request_no`),
KEY `idx_gao_point_redemption_return_time` (`redemption_id`, `returned_at`)
) COMMENT='GAO 积分兑换退货记录';
@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.imyeyu.api.modules.gao.mapper.GaoPointRedeemSkuMapper">
<select id="selectByStoreIdAndId" resultType="com.imyeyu.api.modules.gao.entity.GaoPointRedeemSku">
SELECT * FROM `gao_point_redeem_sku`
WHERE `store_id` = #{storeId} AND `id` = #{id} AND `deleted_at` IS NULL
LIMIT 1
</select>
<select id="selectByStoreSkuUnit" resultType="com.imyeyu.api.modules.gao.entity.GaoPointRedeemSku">
SELECT * FROM `gao_point_redeem_sku`
WHERE `store_id` = #{storeId} AND `sku_id` = #{skuId} AND `sku_unit_id` = #{skuUnitId}
AND `deleted_at` IS NULL
LIMIT 1
</select>
<select id="selectForUpdate" resultType="com.imyeyu.api.modules.gao.entity.GaoPointRedeemSku">
SELECT * FROM `gao_point_redeem_sku`
WHERE `id` = #{id} AND `deleted_at` IS NULL
LIMIT 1
FOR UPDATE
</select>
<sql id="queryWhere">
`r`.`deleted_at` IS NULL
<if test="storeId != null and storeId != ''">AND `r`.`store_id` = #{storeId}</if>
<if test="skuId != null and skuId != ''">AND `r`.`sku_id` = #{skuId}</if>
<if test="status != null">AND `r`.`status` = #{status}</if>
<if test="keyword != null and keyword.trim() != ''">
AND (`p`.`name` LIKE CONCAT('%', #{keyword}, '%') OR `p`.`code` LIKE CONCAT('%', #{keyword}, '%')
OR `k`.`name` LIKE CONCAT('%', #{keyword}, '%') OR `k`.`code` LIKE CONCAT('%', #{keyword}, '%'))
</if>
</sql>
<select id="countByQuery" resultType="long">
SELECT COUNT(1)
FROM `gao_point_redeem_sku` `r`
INNER JOIN `gao_product_sku` `k` ON `k`.`id` = `r`.`sku_id`
INNER JOIN `gao_product` `p` ON `p`.`id` = `k`.`product_id`
WHERE <include refid="queryWhere"/>
</select>
<select id="selectByQuery" resultType="com.imyeyu.api.modules.gao.entity.GaoPointRedeemSku">
SELECT `r`.*
FROM `gao_point_redeem_sku` `r`
INNER JOIN `gao_product_sku` `k` ON `k`.`id` = `r`.`sku_id`
INNER JOIN `gao_product` `p` ON `p`.`id` = `k`.`product_id`
WHERE <include refid="queryWhere"/>
ORDER BY `r`.`created_at` DESC, `r`.`id` DESC
LIMIT #{offset}, #{limit}
</select>
<update id="updateConfig">
UPDATE `gao_point_redeem_sku`
SET `sku_id` = #{skuId},
`sku_unit_id` = #{skuUnitId},
`status` = #{status},
`default_point_cost` = #{defaultPointCost},
`begin_at` = #{beginAt},
`end_at` = #{endAt},
`max_total_quantity` = #{maxTotalQuantity},
`max_daily_quantity` = #{maxDailyQuantity},
`max_monthly_quantity` = #{maxMonthlyQuantity},
`remark` = #{remark},
`updated_at` = #{updatedAt}
WHERE `id` = #{id} AND `deleted_at` IS NULL
</update>
</mapper>
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.imyeyu.api.modules.gao.mapper.GaoPointRedemptionMapper">
<select id="selectByStoreIdAndRequestNo" resultType="com.imyeyu.api.modules.gao.entity.GaoPointRedemption">
SELECT * FROM `gao_point_redemption`
WHERE `store_id` = #{storeId} AND `request_no` = #{requestNo} AND `deleted_at` IS NULL
LIMIT 1
</select>
<select id="selectByStoreIdAndId" resultType="com.imyeyu.api.modules.gao.entity.GaoPointRedemption">
SELECT * FROM `gao_point_redemption`
WHERE `store_id` = #{storeId} AND `id` = #{id} AND `deleted_at` IS NULL
LIMIT 1
</select>
<select id="selectForUpdate" resultType="com.imyeyu.api.modules.gao.entity.GaoPointRedemption">
SELECT * FROM `gao_point_redemption`
WHERE `id` = #{id} AND `deleted_at` IS NULL
LIMIT 1
FOR UPDATE
</select>
<sql id="queryWhere">
`r`.`deleted_at` IS NULL
<if test="storeId != null and storeId != ''">AND `r`.`store_id` = #{storeId}</if>
<if test="customerId != null and customerId != ''">AND `r`.`customer_id` = #{customerId}</if>
<if test="redeemSkuId != null and redeemSkuId != ''">AND `r`.`redeem_sku_id_snapshot` = #{redeemSkuId}</if>
<if test="skuIdSnapshot != null and skuIdSnapshot != ''">AND `r`.`sku_id_snapshot` = #{skuIdSnapshot}</if>
<if test="status != null">AND `r`.`status` = #{status}</if>
<if test="keyword != null and keyword.trim() != ''">
AND (`r`.`product_name_snapshot` LIKE CONCAT('%', #{keyword}, '%')
OR `r`.`sku_code_snapshot` LIKE CONCAT('%', #{keyword}, '%')
OR `r`.`sku_name_snapshot` LIKE CONCAT('%', #{keyword}, '%')
OR `c`.`code` LIKE CONCAT('%', #{keyword}, '%')
OR `c`.`name` LIKE CONCAT('%', #{keyword}, '%')
OR `c`.`telephone` LIKE CONCAT('%', #{keyword}, '%')
OR `c`.`name_pinyin_full` LIKE CONCAT(#{keyword}, '%')
OR `c`.`name_pinyin_initial` LIKE CONCAT(#{keyword}, '%')
OR `c`.`name_pinyin_mixed` LIKE CONCAT(#{keyword}, '%'))
</if>
<if test="beginAt != null">AND `r`.`redeemed_at` &gt;= #{beginAt}</if>
<if test="endAt != null">AND `r`.`redeemed_at` &lt;= #{endAt}</if>
</sql>
<select id="countByQuery" resultType="long">
SELECT COUNT(1)
FROM `gao_point_redemption` `r`
LEFT JOIN `gao_customer` `c` ON `c`.`id` = `r`.`customer_id`
WHERE <include refid="queryWhere"/>
</select>
<select id="selectByQuery" resultType="com.imyeyu.api.modules.gao.entity.GaoPointRedemption">
SELECT `r`.*
FROM `gao_point_redemption` `r`
LEFT JOIN `gao_customer` `c` ON `c`.`id` = `r`.`customer_id`
WHERE <include refid="queryWhere"/>
ORDER BY `r`.`redeemed_at` DESC, `r`.`created_at` DESC, `r`.`id` DESC
LIMIT #{offset}, #{limit}
</select>
<select id="sumValidQuantity" resultType="java.math.BigDecimal">
SELECT COALESCE(SUM(`quantity` - `returned_quantity`), 0)
FROM `gao_point_redemption`
WHERE `store_id` = #{storeId}
AND `customer_id` = #{customerId}
AND `sku_id_snapshot` = #{skuId}
AND `status` IN ('COMPLETED', 'PARTIALLY_RETURNED')
AND `deleted_at` IS NULL
<if test="beginAt != null">AND `redeemed_at` &gt;= #{beginAt}</if>
<if test="endAt != null">AND `redeemed_at` &lt;= #{endAt}</if>
</select>
</mapper>
@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.imyeyu.api.modules.gao.mapper.GaoPointRedemptionReturnMapper">
<select id="selectByRedemptionId" resultType="com.imyeyu.api.modules.gao.entity.GaoPointRedemptionReturn">
SELECT * FROM `gao_point_redemption_return`
WHERE `redemption_id` = #{redemptionId} AND `deleted_at` IS NULL
ORDER BY `returned_at`, `created_at`, `id`
</select>
<select id="selectByRedemptionIdList" resultType="com.imyeyu.api.modules.gao.entity.GaoPointRedemptionReturn">
SELECT * FROM `gao_point_redemption_return`
WHERE `redemption_id` IN
<foreach collection="redemptionIdList" item="redemptionId" separator="," open="(" close=")">
#{redemptionId}
</foreach>
AND `deleted_at` IS NULL
ORDER BY `redemption_id`, `returned_at`, `created_at`, `id`
</select>
<select id="selectByRedemptionIdAndRequestNo" resultType="com.imyeyu.api.modules.gao.entity.GaoPointRedemptionReturn">
SELECT * FROM `gao_point_redemption_return`
WHERE `redemption_id` = #{redemptionId} AND `request_no` = #{requestNo} AND `deleted_at` IS NULL
LIMIT 1
</select>
<select id="selectForUpdate" resultType="com.imyeyu.api.modules.gao.entity.GaoPointRedemptionReturn">
SELECT * FROM `gao_point_redemption_return`
WHERE `id` = #{id} AND `deleted_at` IS NULL
LIMIT 1
FOR UPDATE
</select>
</mapper>