Merge branch 'master' of http://git.lionquexpress.com/wuweihua/BMS
This commit is contained in:
@@ -27,6 +27,7 @@ import com.bms.common.enums.BusinessType;
|
||||
import com.bms.common.utils.MessageUtils;
|
||||
import com.bms.common.utils.StringUtils;
|
||||
import com.bms.price.domain.PrcCustomerPriceSet;
|
||||
import com.bms.price.domain.PrcPriceSetUser;
|
||||
import com.bms.price.domain.PrcPriceExcelFile;
|
||||
import com.bms.price.domain.PrcPriceSet;
|
||||
import com.bms.price.domain.PrcPriceSetDetail;
|
||||
@@ -386,4 +387,30 @@ public class PriceSetController extends BaseController
|
||||
{
|
||||
return toAjax(priceSetService.deleteCustomerByIds(customerPricesetIds));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('price:set:list')")
|
||||
@GetMapping("/viewer/list")
|
||||
public TableDataInfo viewerList(PrcPriceSetUser query)
|
||||
{
|
||||
startPage();
|
||||
List<PrcPriceSetUser> list = priceSetService.selectViewerList(query);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('price:set:edit')")
|
||||
@Log(title = "Package viewer bind", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/viewer")
|
||||
public AjaxResult addViewer(@RequestBody PrcPriceSetUser row)
|
||||
{
|
||||
row.setCreateBy(getUsername());
|
||||
return toAjax(priceSetService.insertViewer(row));
|
||||
}
|
||||
|
||||
@PreAuthorize("@ss.hasPermi('price:set:edit')")
|
||||
@Log(title = "Package viewer bind", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/viewer/{psuIds}")
|
||||
public AjaxResult removeViewer(@PathVariable Long[] psuIds)
|
||||
{
|
||||
return toAjax(priceSetService.deleteViewerByIds(psuIds));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@ public class PrcPriceSet extends BaseEntity
|
||||
private List<PrcPriceSetDetail> details;
|
||||
private List<PrcPriceSetVersion> versions;
|
||||
private List<PrcCustomerPriceSet> customers;
|
||||
/** viewers explicitly bound to this package */
|
||||
private List<PrcPriceSetUser> viewers;
|
||||
/** async save task id (not persisted) */
|
||||
private String saveTaskId;
|
||||
/** Y: ignored on save; library pull only via /detail/pullFromLibrary */
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.bms.price.domain;
|
||||
|
||||
import com.bms.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/** Package viewer bind: prc_price_set_user */
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PrcPriceSetUser extends BaseEntity
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long psuId;
|
||||
private Long priceSetId;
|
||||
private Long userId;
|
||||
/** login account */
|
||||
private String userName;
|
||||
/** display only, not a table column */
|
||||
private String nickName;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.bms.price.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import com.bms.price.domain.PrcPriceSetUser;
|
||||
|
||||
public interface PrcPriceSetUserMapper
|
||||
{
|
||||
PrcPriceSetUser selectPrcPriceSetUserById(Long psuId);
|
||||
|
||||
List<PrcPriceSetUser> selectPrcPriceSetUserList(PrcPriceSetUser query);
|
||||
|
||||
int insertPrcPriceSetUser(PrcPriceSetUser row);
|
||||
|
||||
int deletePrcPriceSetUserByIds(Long[] psuIds);
|
||||
|
||||
int deleteByPriceSetId(Long priceSetId);
|
||||
|
||||
int countBySetAndUser(@Param("priceSetId") Long priceSetId, @Param("userId") Long userId);
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import com.bms.price.domain.PrcPriceSet;
|
||||
import com.bms.price.domain.PrcPriceSetCheckItem;
|
||||
import com.bms.price.domain.PrcPriceSetDetail;
|
||||
import com.bms.price.domain.PrcPriceSetSaveTask;
|
||||
import com.bms.price.domain.PrcPriceSetUser;
|
||||
|
||||
/**
|
||||
* 价格套餐 服务层
|
||||
@@ -91,6 +92,12 @@ public interface IPrcPriceSetService
|
||||
|
||||
public int deleteCustomerByIds(Long[] customerPricesetIds);
|
||||
|
||||
public List<PrcPriceSetUser> selectViewerList(PrcPriceSetUser query);
|
||||
|
||||
public int insertViewer(PrcPriceSetUser row);
|
||||
|
||||
public int deleteViewerByIds(Long[] psuIds);
|
||||
|
||||
/** chain expire_time = next version effective_time, then refresh 0/3/1/2 */
|
||||
public int refreshAllVersionStatus();
|
||||
|
||||
|
||||
+67
@@ -18,6 +18,7 @@ import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.bms.common.annotation.DataScope;
|
||||
import com.bms.common.exception.ServiceException;
|
||||
import com.bms.common.utils.DateUtils;
|
||||
import com.bms.common.utils.MessageUtils;
|
||||
@@ -29,6 +30,7 @@ import com.bms.price.domain.BmsProductCountry;
|
||||
import com.bms.price.domain.PrcCustomerPriceSet;
|
||||
import com.bms.price.domain.PrcPriceExcelFile;
|
||||
import com.bms.price.domain.PrcPriceSet;
|
||||
import com.bms.price.domain.PrcPriceSetUser;
|
||||
import com.bms.price.domain.PrcPriceSetCheckItem;
|
||||
import com.bms.price.domain.PrcPriceSetDetail;
|
||||
import com.bms.price.domain.PrcPriceSetProduct;
|
||||
@@ -42,9 +44,12 @@ import com.bms.price.mapper.PrcCustomerPriceSetMapper;
|
||||
import com.bms.price.mapper.PrcPriceSetDetailMapper;
|
||||
import com.bms.price.mapper.PrcPriceSetMapper;
|
||||
import com.bms.price.mapper.PrcPriceSetProductMapper;
|
||||
import com.bms.price.mapper.PrcPriceSetUserMapper;
|
||||
import com.bms.price.mapper.PrcPriceSetVersionMapper;
|
||||
import com.bms.price.mapper.PrcSurchargeMapper;
|
||||
import com.bms.price.mapper.PrcSurchargeRelMapper;
|
||||
import com.bms.common.core.domain.entity.SysUser;
|
||||
import com.bms.system.mapper.SysUserMapper;
|
||||
import com.bms.price.service.IBmsProductService;
|
||||
import com.bms.price.service.IPrcPriceExcelFileService;
|
||||
import com.bms.price.service.IPrcPriceSetService;
|
||||
@@ -98,6 +103,12 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
@Autowired
|
||||
private PrcCustomerPriceSetMapper customerMapper;
|
||||
|
||||
@Autowired
|
||||
private PrcPriceSetUserMapper priceSetUserMapper;
|
||||
|
||||
@Autowired
|
||||
private SysUserMapper sysUserMapper;
|
||||
|
||||
@Autowired
|
||||
private BmsProductCountryMapper productCountryMapper;
|
||||
|
||||
@@ -132,9 +143,19 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Price-set list data scope: bound customer's sales user (same as customer list),
|
||||
* package creator, or explicit viewer bind. Super admin skips filter in DataScopeAspect.
|
||||
*/
|
||||
@Override
|
||||
@DataScope(deptAlias = "su", deptField = "dept_id", userAlias = "su", userField = "user_id",
|
||||
permission = "price:set:list")
|
||||
public List<PrcPriceSet> selectPrcPriceSetList(PrcPriceSet set)
|
||||
{
|
||||
if (set != null)
|
||||
{
|
||||
set.getParams().put("viewerUserId", SecurityUtils.getUserId());
|
||||
}
|
||||
List<PrcPriceSet> list = setMapper.selectPrcPriceSetList(set);
|
||||
for (PrcPriceSet item : list)
|
||||
{
|
||||
@@ -2223,6 +2244,49 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
return customerMapper.deletePrcCustomerPriceSetByIds(customerPricesetIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PrcPriceSetUser> selectViewerList(PrcPriceSetUser query)
|
||||
{
|
||||
return priceSetUserMapper.selectPrcPriceSetUserList(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public int insertViewer(PrcPriceSetUser row)
|
||||
{
|
||||
if (row == null || row.getPriceSetId() == null || row.getUserId() == null)
|
||||
{
|
||||
throw new ServiceException("price set user bind requires priceSetId and userId");
|
||||
}
|
||||
requireSet(row.getPriceSetId());
|
||||
if (priceSetUserMapper.countBySetAndUser(row.getPriceSetId(), row.getUserId()) > 0)
|
||||
{
|
||||
throw new ServiceException("user already bound to this price set");
|
||||
}
|
||||
SysUser user = sysUserMapper.selectUserById(row.getUserId());
|
||||
if (user == null)
|
||||
{
|
||||
throw new ServiceException("user not found");
|
||||
}
|
||||
row.setUserName(user.getUserName());
|
||||
if (StringUtils.isEmpty(row.getCreateBy()))
|
||||
{
|
||||
row.setCreateBy(SecurityUtils.getUsername());
|
||||
}
|
||||
return priceSetUserMapper.insertPrcPriceSetUser(row);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public int deleteViewerByIds(Long[] psuIds)
|
||||
{
|
||||
if (psuIds == null || psuIds.length == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return priceSetUserMapper.deletePrcPriceSetUserByIds(psuIds);
|
||||
}
|
||||
|
||||
private void replaceChildren(PrcPriceSet set)
|
||||
{
|
||||
saveOrUpdateVersion(set);
|
||||
@@ -2989,6 +3053,9 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
PrcCustomerPriceSet cquery = new PrcCustomerPriceSet();
|
||||
cquery.setPriceSetId(priceSetId);
|
||||
set.setCustomers(customerMapper.selectPrcCustomerPriceSetList(cquery));
|
||||
PrcPriceSetUser uquery = new PrcPriceSetUser();
|
||||
uquery.setPriceSetId(priceSetId);
|
||||
set.setViewers(priceSetUserMapper.selectPrcPriceSetUserList(uquery));
|
||||
}
|
||||
|
||||
private void fillVersionChildren(PrcPriceSetVersion version)
|
||||
|
||||
@@ -81,6 +81,40 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
)
|
||||
)
|
||||
</if>
|
||||
<!-- Data scope: customer sales / creator / explicit viewer bind.
|
||||
Super admin / DATA_SCOPE_ALL leaves params.dataScope empty. -->
|
||||
<if test="params != null and params.dataScope != null and params.dataScope != ''">
|
||||
AND (
|
||||
EXISTS (
|
||||
SELECT 1
|
||||
FROM prc_customer_price_set cps
|
||||
INNER JOIN ctr_customer c
|
||||
ON c.customer_id = cps.customer_id
|
||||
AND ifnull(c.del_flag, '0') = '0'
|
||||
INNER JOIN sys_user su
|
||||
ON su.del_flag = '0'
|
||||
AND (su.user_name = c.sales_user_id
|
||||
OR su.user_id = c.sales_user_id + 0)
|
||||
WHERE cps.price_set_id = s.price_set_id
|
||||
${params.dataScope}
|
||||
)
|
||||
OR EXISTS (
|
||||
SELECT 1
|
||||
FROM sys_user su
|
||||
WHERE su.del_flag = '0'
|
||||
AND su.user_name = s.created_by
|
||||
${params.dataScope}
|
||||
)
|
||||
<if test="params.viewerUserId != null">
|
||||
OR EXISTS (
|
||||
SELECT 1
|
||||
FROM prc_price_set_user psu
|
||||
WHERE psu.price_set_id = s.price_set_id
|
||||
AND psu.user_id = #{params.viewerUserId}
|
||||
)
|
||||
</if>
|
||||
)
|
||||
</if>
|
||||
</where>
|
||||
order by s.price_set_id desc
|
||||
</select>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<?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.bms.price.mapper.PrcPriceSetUserMapper">
|
||||
|
||||
<resultMap type="PrcPriceSetUser" id="PrcPriceSetUserResult">
|
||||
<id property="psuId" column="psu_id" />
|
||||
<result property="priceSetId" column="price_set_id" />
|
||||
<result property="userId" column="user_id" />
|
||||
<result property="userName" column="user_name" />
|
||||
<result property="nickName" column="nick_name" />
|
||||
<result property="createBy" column="created_by" />
|
||||
<result property="createTime" column="create_time" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectVo">
|
||||
select psu.psu_id, psu.price_set_id, psu.user_id, psu.user_name,
|
||||
u.nick_name, psu.created_by, psu.create_time
|
||||
from prc_price_set_user psu
|
||||
left join sys_user u on u.user_id = psu.user_id
|
||||
</sql>
|
||||
|
||||
<select id="selectPrcPriceSetUserById" parameterType="Long" resultMap="PrcPriceSetUserResult">
|
||||
<include refid="selectVo"/>
|
||||
where psu.psu_id = #{psuId}
|
||||
</select>
|
||||
|
||||
<select id="selectPrcPriceSetUserList" parameterType="PrcPriceSetUser" resultMap="PrcPriceSetUserResult">
|
||||
<include refid="selectVo"/>
|
||||
<where>
|
||||
<if test="priceSetId != null">AND psu.price_set_id = #{priceSetId}</if>
|
||||
<if test="userId != null">AND psu.user_id = #{userId}</if>
|
||||
<if test="userName != null and userName != ''">AND psu.user_name = #{userName}</if>
|
||||
</where>
|
||||
order by psu.psu_id asc
|
||||
</select>
|
||||
|
||||
<select id="countBySetAndUser" resultType="int">
|
||||
select count(1) from prc_price_set_user
|
||||
where price_set_id = #{priceSetId} and user_id = #{userId}
|
||||
</select>
|
||||
|
||||
<insert id="insertPrcPriceSetUser" parameterType="PrcPriceSetUser" useGeneratedKeys="true" keyProperty="psuId">
|
||||
insert into prc_price_set_user (price_set_id, user_id, user_name, created_by, create_time)
|
||||
values (#{priceSetId}, #{userId}, #{userName}, #{createBy}, sysdate())
|
||||
</insert>
|
||||
|
||||
<delete id="deletePrcPriceSetUserByIds" parameterType="Long">
|
||||
delete from prc_price_set_user where psu_id in
|
||||
<foreach collection="array" item="id" open="(" separator="," close=")">#{id}</foreach>
|
||||
</delete>
|
||||
|
||||
<delete id="deleteByPriceSetId" parameterType="Long">
|
||||
delete from prc_price_set_user where price_set_id = #{priceSetId}
|
||||
</delete>
|
||||
</mapper>
|
||||
@@ -802,6 +802,23 @@ CREATE TABLE `prc_customer_price_set` (
|
||||
CONSTRAINT `fk_customer_price_set` FOREIGN KEY (`price_set_id`) REFERENCES `prc_price_set` (`price_set_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='客户套餐表-客户某时间段内使用的套餐';
|
||||
|
||||
-- ----------------------------
|
||||
-- 表结构:`prc_price_set_user`
|
||||
-- ----------------------------
|
||||
CREATE TABLE `prc_price_set_user` (
|
||||
`psu_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`price_set_id` bigint(20) NOT NULL COMMENT '价格套餐id',
|
||||
`user_id` bigint(20) NOT NULL COMMENT '用户id',
|
||||
`user_name` varchar(64) NOT NULL DEFAULT '' COMMENT '登录账号',
|
||||
`created_by` varchar(64) DEFAULT '' COMMENT '创建人',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
PRIMARY KEY (`psu_id`),
|
||||
UNIQUE KEY `uk_psu_set_user` (`price_set_id`,`user_id`),
|
||||
KEY `idx_psu_user` (`user_id`),
|
||||
KEY `idx_psu_set` (`price_set_id`),
|
||||
CONSTRAINT `fk_psu_set` FOREIGN KEY (`price_set_id`) REFERENCES `prc_price_set` (`price_set_id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='套餐可见用户绑定';
|
||||
|
||||
-- ----------------------------
|
||||
-- 表结构:`prc_income_bill`
|
||||
-- ----------------------------
|
||||
|
||||
@@ -0,0 +1,927 @@
|
||||
-- =============================================================================
|
||||
-- Merged price upgrade script
|
||||
-- Sources (in order):
|
||||
-- - unify_price_type_version.sql
|
||||
-- - prc_price_set_is_del_alter.sql
|
||||
-- - prc_price_set_product_effect_alter.sql
|
||||
-- - prc_price_excel_file.sql
|
||||
-- - prc_price_excel_psv_alter.sql
|
||||
-- - prc_order_bill_fail_snapshot_alter.sql
|
||||
-- - order_bill_query_menu.sql
|
||||
-- - order_bill_rebill_menu.sql
|
||||
-- Safe to re-run where original scripts used information_schema guards.
|
||||
-- Run once on target DB. Backup first if production.
|
||||
-- Generated: 2026-10-18
|
||||
-- =============================================================================
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET @db := DATABASE();
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 1) unify PRODUCT / REDLINE / SALES into version + product/detail
|
||||
-- source: unify_price_type_version.sql
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- Unify PRODUCT / REDLINE / SALES into prc_price_set_version + product/detail
|
||||
-- Run once on existing DB. Safe-ish: checks columns via information_schema patterns where needed.
|
||||
-- price_type: PRODUCT | REDLINE | SALES
|
||||
|
||||
-- ========== 1) prc_price_set_version: price_type + soft FK ==========
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_version ADD COLUMN price_type varchar(20) NOT NULL DEFAULT ''SALES'' COMMENT ''价格类型 PRODUCT产品价/REDLINE红线价/SALES销售价'' AFTER price_set_id',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_version' AND COLUMN_NAME = 'price_type'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
UPDATE prc_price_set_version SET price_type = 'SALES' WHERE price_type IS NULL OR price_type = '';
|
||||
|
||||
-- drop FK fk_psv_set if exists
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) > 0,
|
||||
'ALTER TABLE prc_price_set_version DROP FOREIGN KEY fk_psv_set',
|
||||
'SELECT 1')
|
||||
FROM information_schema.TABLE_CONSTRAINTS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_version' AND CONSTRAINT_NAME = 'fk_psv_set'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- price_set_id nullable
|
||||
ALTER TABLE prc_price_set_version MODIFY COLUMN price_set_id bigint(20) DEFAULT NULL COMMENT '价格套餐id(弱关联;PRODUCT/REDLINE为空)';
|
||||
|
||||
-- generated key for uniqueness (NULL price_set_id -> 0)
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_version ADD COLUMN price_set_id_key bigint(20) GENERATED ALWAYS AS (IFNULL(price_set_id,0)) STORED COMMENT ''唯一键辅助:空price_set_id视为0'' AFTER price_set_id',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_version' AND COLUMN_NAME = 'price_set_id_key'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- replace unique keys
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) > 0, 'ALTER TABLE prc_price_set_version DROP INDEX uk_psv_set_no', 'SELECT 1')
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_version' AND INDEX_NAME = 'uk_psv_set_no' LIMIT 1
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) > 0, 'ALTER TABLE prc_price_set_version DROP INDEX uk_psv_set_seq', 'SELECT 1')
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_version' AND INDEX_NAME = 'uk_psv_set_seq' LIMIT 1
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_version ADD UNIQUE KEY uk_psv_type_set_no (price_type, price_set_id_key, version_no)',
|
||||
'SELECT 1')
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_version' AND INDEX_NAME = 'uk_psv_type_set_no' LIMIT 1
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_version ADD UNIQUE KEY uk_psv_type_set_seq (price_type, price_set_id_key, version_seq)',
|
||||
'SELECT 1')
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_version' AND INDEX_NAME = 'uk_psv_type_set_seq' LIMIT 1
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_version ADD KEY idx_psv_type_eff (price_type, status, effective_time)',
|
||||
'SELECT 1')
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_version' AND INDEX_NAME = 'idx_psv_type_eff' LIMIT 1
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- ========== 2) prc_price_set_product: price_type, drop price_set_id ==========
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_product ADD COLUMN price_type varchar(20) NOT NULL DEFAULT ''SALES'' COMMENT ''价格类型 PRODUCT/REDLINE/SALES'' AFTER psp_id',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_product' AND COLUMN_NAME = 'price_type'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
UPDATE prc_price_set_product psp
|
||||
INNER JOIN prc_price_set_version v ON v.psv_id = psp.psv_id
|
||||
SET psp.price_type = IFNULL(NULLIF(v.price_type,''), 'SALES')
|
||||
WHERE psp.price_type IS NULL OR psp.price_type = '' OR psp.price_type = 'SALES';
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) > 0, 'ALTER TABLE prc_price_set_product DROP FOREIGN KEY fk_psp_set', 'SELECT 1')
|
||||
FROM information_schema.TABLE_CONSTRAINTS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_product' AND CONSTRAINT_NAME = 'fk_psp_set'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) > 0, 'ALTER TABLE prc_price_set_product DROP COLUMN price_set_id', 'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_product' AND COLUMN_NAME = 'price_set_id'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0, 'ALTER TABLE prc_price_set_product ADD KEY idx_psp_type_psv (price_type, psv_id)', 'SELECT 1')
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_product' AND INDEX_NAME = 'idx_psp_type_psv' LIMIT 1
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- ========== 3) prc_price_set_detail: price_type, catalog cols, drop price_set_id ==========
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_detail ADD COLUMN price_type varchar(20) NOT NULL DEFAULT ''SALES'' COMMENT ''价格类型 PRODUCT/REDLINE/SALES'' AFTER psd_id',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_detail' AND COLUMN_NAME = 'price_type'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
UPDATE prc_price_set_detail d
|
||||
INNER JOIN prc_price_set_version v ON v.psv_id = d.psv_id
|
||||
SET d.price_type = IFNULL(NULLIF(v.price_type,''), 'SALES')
|
||||
WHERE d.psv_id IS NOT NULL;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_detail ADD COLUMN size_limit varchar(1000) DEFAULT NULL COMMENT ''尺寸限制'' AFTER fv_registration_fee',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_detail' AND COLUMN_NAME = 'size_limit'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_detail ADD COLUMN last_mile varchar(500) DEFAULT NULL COMMENT ''尾程派送说明'' AFTER size_limit',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_detail' AND COLUMN_NAME = 'last_mile'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_detail ADD COLUMN lead_time varchar(100) DEFAULT NULL COMMENT ''参考时效'' AFTER last_mile',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_detail' AND COLUMN_NAME = 'lead_time'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) > 0, 'ALTER TABLE prc_price_set_detail DROP FOREIGN KEY fk_psd_set', 'SELECT 1')
|
||||
FROM information_schema.TABLE_CONSTRAINTS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_detail' AND CONSTRAINT_NAME = 'fk_psd_set'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) > 0, 'ALTER TABLE prc_price_set_detail DROP COLUMN price_set_id', 'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_detail' AND COLUMN_NAME = 'price_set_id'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0, 'ALTER TABLE prc_price_set_detail ADD KEY idx_psd_type_psv (price_type, psv_id)', 'SELECT 1')
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_detail' AND INDEX_NAME = 'idx_psd_type_psv' LIMIT 1
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- ========== 4) Migrate PRODUCT catalog -> version snapshot ==========
|
||||
-- Create one version per distinct effective_date group from active product rows (status in 0,1),
|
||||
-- collapsed into global versions ordered by effective_date.
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp_product_version_map;
|
||||
CREATE TEMPORARY TABLE tmp_product_version_map (
|
||||
old_product_id bigint(20) NOT NULL PRIMARY KEY,
|
||||
new_psv_id bigint(20) NOT NULL,
|
||||
new_psp_id bigint(20) DEFAULT NULL
|
||||
);
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp_product_eff;
|
||||
CREATE TEMPORARY TABLE tmp_product_eff AS
|
||||
SELECT DISTINCT effective_date
|
||||
FROM product
|
||||
WHERE IFNULL(is_del,'0') = '0'
|
||||
ORDER BY IFNULL(effective_date, '1970-01-01');
|
||||
|
||||
-- Build PRODUCT versions from distinct effective dates (empty catalog skipped)
|
||||
INSERT INTO prc_price_set_version (
|
||||
price_set_id, price_type, version_no, version_seq, effective_time, expire_time, status,
|
||||
price_build_mode, created_by, create_time
|
||||
)
|
||||
SELECT
|
||||
NULL,
|
||||
'PRODUCT',
|
||||
CONCAT('V', (@seq := @seq + 1)),
|
||||
@seq,
|
||||
e.effective_date,
|
||||
NULL,
|
||||
CASE
|
||||
WHEN e.effective_date IS NOT NULL AND e.effective_date > NOW() THEN '0'
|
||||
ELSE '1'
|
||||
END,
|
||||
'IMPORT',
|
||||
'migrate',
|
||||
NOW()
|
||||
FROM tmp_product_eff e
|
||||
CROSS JOIN (SELECT @seq := IFNULL((SELECT MAX(version_seq) FROM prc_price_set_version WHERE price_type='PRODUCT' AND IFNULL(price_set_id,0)=0), 0)) s
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM prc_price_set_version v
|
||||
WHERE v.price_type = 'PRODUCT' AND IFNULL(v.price_set_id,0) = 0
|
||||
)
|
||||
ORDER BY IFNULL(e.effective_date, '1970-01-01');
|
||||
|
||||
-- If versions already exist (re-run), skip product migrate body when PRODUCT versions already present with products
|
||||
SET @product_migrated := (
|
||||
SELECT COUNT(*) FROM prc_price_set_product WHERE price_type = 'PRODUCT'
|
||||
);
|
||||
|
||||
-- Chain expire_time for PRODUCT versions
|
||||
UPDATE prc_price_set_version v
|
||||
LEFT JOIN prc_price_set_version n
|
||||
ON n.price_type = 'PRODUCT' AND IFNULL(n.price_set_id,0)=0 AND n.version_seq = v.version_seq + 1
|
||||
SET v.expire_time = n.effective_time,
|
||||
v.status = CASE
|
||||
WHEN n.psv_id IS NOT NULL AND n.effective_time IS NOT NULL AND n.effective_time <= NOW() THEN '2'
|
||||
WHEN v.effective_time IS NOT NULL AND v.effective_time > NOW() THEN '0'
|
||||
WHEN v.effective_time IS NULL OR v.effective_time <= NOW() THEN '1'
|
||||
ELSE v.status
|
||||
END
|
||||
WHERE v.price_type = 'PRODUCT' AND IFNULL(v.price_set_id,0)=0;
|
||||
|
||||
-- Map each product row to version by effective_date match (only if not yet migrated)
|
||||
INSERT INTO prc_price_set_product (
|
||||
price_type, psv_id, product_code, product_name, service_level, cargo_attr, dest_region,
|
||||
update_note, tax_mode, source_product_id, source_sheet, create_time
|
||||
)
|
||||
SELECT
|
||||
'PRODUCT',
|
||||
v.psv_id,
|
||||
p.product_code,
|
||||
p.product_name,
|
||||
p.service_level,
|
||||
p.cargo_attr,
|
||||
p.dest_region,
|
||||
p.update_note,
|
||||
IFNULL(p.tax_mode, 'TAX_INCLUDED'),
|
||||
p.product_id,
|
||||
p.source_sheet,
|
||||
IFNULL(p.create_time, NOW())
|
||||
FROM product p
|
||||
INNER JOIN prc_price_set_version v
|
||||
ON v.price_type = 'PRODUCT' AND IFNULL(v.price_set_id,0)=0
|
||||
AND (
|
||||
(p.effective_date IS NULL AND v.effective_time IS NULL)
|
||||
OR p.effective_date = v.effective_time
|
||||
)
|
||||
WHERE IFNULL(p.is_del,'0') = '0'
|
||||
AND @product_migrated = 0
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM prc_price_set_product x
|
||||
WHERE x.psv_id = v.psv_id AND x.product_code = p.product_code
|
||||
);
|
||||
|
||||
INSERT INTO tmp_product_version_map (old_product_id, new_psv_id, new_psp_id)
|
||||
SELECT p.product_id, psp.psv_id, psp.psp_id
|
||||
FROM product p
|
||||
INNER JOIN prc_price_set_product psp
|
||||
ON psp.price_type = 'PRODUCT' AND psp.source_product_id = p.product_id;
|
||||
|
||||
INSERT INTO prc_price_set_detail (
|
||||
price_type, psv_id, psp_id, product_code, product_name, country_code, country_name,
|
||||
zone_id, zone_code, zone_name, weight_label, weight_min, weight_max, product_country_id,
|
||||
fv_value, fv_registration_fee, size_limit, last_mile, lead_time, round_mode,
|
||||
effective_date, expire_date, create_time
|
||||
)
|
||||
SELECT
|
||||
'PRODUCT',
|
||||
m.new_psv_id,
|
||||
m.new_psp_id,
|
||||
c.product_code,
|
||||
p.product_name,
|
||||
c.country_code,
|
||||
c.country_name,
|
||||
c.zone_id,
|
||||
c.zone_code,
|
||||
c.zone_name,
|
||||
CASE
|
||||
WHEN c.weight_min IS NULL AND c.weight_max IS NULL THEN NULL
|
||||
ELSE CONCAT(
|
||||
IFNULL(TRIM(TRAILING '0' FROM TRIM(TRAILING '.' FROM CAST(c.weight_min AS CHAR))), ''),
|
||||
'<W≤',
|
||||
IFNULL(TRIM(TRAILING '0' FROM TRIM(TRAILING '.' FROM CAST(c.weight_max AS CHAR))), '')
|
||||
)
|
||||
END,
|
||||
c.weight_min,
|
||||
c.weight_max,
|
||||
c.detail_id,
|
||||
c.freight_price,
|
||||
c.registration_fee,
|
||||
c.size_limit,
|
||||
c.last_mile,
|
||||
c.lead_time,
|
||||
'HALF_UP',
|
||||
DATE(c.effective_date),
|
||||
DATE(c.expire_date),
|
||||
IFNULL(c.create_time, NOW())
|
||||
FROM product_country c
|
||||
INNER JOIN tmp_product_version_map m ON m.old_product_id = c.product_id
|
||||
INNER JOIN product p ON p.product_id = c.product_id
|
||||
WHERE IFNULL(c.is_del,'0') = '0'
|
||||
AND @product_migrated = 0
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM prc_price_set_detail d WHERE d.product_country_id = c.detail_id AND d.price_type = 'PRODUCT'
|
||||
);
|
||||
|
||||
-- Remap PRODUCT surcharge_rel to psp_id / psd_id
|
||||
UPDATE prc_surcharge_rel r
|
||||
INNER JOIN tmp_product_version_map m ON m.old_product_id = r.product_id
|
||||
SET r.product_id = m.new_psp_id
|
||||
WHERE r.price_type = 'PRODUCT' AND IFNULL(r.is_del,'0') = '0'
|
||||
AND @product_migrated = 0;
|
||||
|
||||
UPDATE prc_surcharge_rel r
|
||||
INNER JOIN prc_price_set_detail d ON d.price_type = 'PRODUCT' AND d.product_country_id = r.detail_id
|
||||
SET r.detail_id = d.psd_id
|
||||
WHERE r.price_type = 'PRODUCT' AND r.detail_id IS NOT NULL AND IFNULL(r.is_del,'0') = '0'
|
||||
AND @product_migrated = 0;
|
||||
|
||||
-- ========== 5) Migrate REDLINE catalog ==========
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp_redline_version_map;
|
||||
CREATE TEMPORARY TABLE tmp_redline_version_map (
|
||||
old_product_id bigint(20) NOT NULL PRIMARY KEY,
|
||||
new_psv_id bigint(20) NOT NULL,
|
||||
new_psp_id bigint(20) DEFAULT NULL
|
||||
);
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp_redline_eff;
|
||||
CREATE TEMPORARY TABLE tmp_redline_eff AS
|
||||
SELECT DISTINCT effective_date
|
||||
FROM redline_product
|
||||
WHERE IFNULL(is_del,'0') = '0'
|
||||
ORDER BY IFNULL(effective_date, '1970-01-01');
|
||||
|
||||
INSERT INTO prc_price_set_version (
|
||||
price_set_id, price_type, version_no, version_seq, effective_time, expire_time, status,
|
||||
price_build_mode, created_by, create_time
|
||||
)
|
||||
SELECT
|
||||
NULL,
|
||||
'REDLINE',
|
||||
CONCAT('V', (@rseq := @rseq + 1)),
|
||||
@rseq,
|
||||
e.effective_date,
|
||||
NULL,
|
||||
CASE
|
||||
WHEN e.effective_date IS NOT NULL AND e.effective_date > NOW() THEN '0'
|
||||
ELSE '1'
|
||||
END,
|
||||
'IMPORT',
|
||||
'migrate',
|
||||
NOW()
|
||||
FROM tmp_redline_eff e
|
||||
CROSS JOIN (SELECT @rseq := IFNULL((SELECT MAX(version_seq) FROM prc_price_set_version WHERE price_type='REDLINE' AND IFNULL(price_set_id,0)=0), 0)) s
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM prc_price_set_version v
|
||||
WHERE v.price_type = 'REDLINE' AND IFNULL(v.price_set_id,0) = 0
|
||||
)
|
||||
ORDER BY IFNULL(e.effective_date, '1970-01-01');
|
||||
|
||||
SET @redline_migrated := (
|
||||
SELECT COUNT(*) FROM prc_price_set_product WHERE price_type = 'REDLINE'
|
||||
);
|
||||
|
||||
UPDATE prc_price_set_version v
|
||||
LEFT JOIN prc_price_set_version n
|
||||
ON n.price_type = 'REDLINE' AND IFNULL(n.price_set_id,0)=0 AND n.version_seq = v.version_seq + 1
|
||||
SET v.expire_time = n.effective_time,
|
||||
v.status = CASE
|
||||
WHEN n.psv_id IS NOT NULL AND n.effective_time IS NOT NULL AND n.effective_time <= NOW() THEN '2'
|
||||
WHEN v.effective_time IS NOT NULL AND v.effective_time > NOW() THEN '0'
|
||||
WHEN v.effective_time IS NULL OR v.effective_time <= NOW() THEN '1'
|
||||
ELSE v.status
|
||||
END
|
||||
WHERE v.price_type = 'REDLINE' AND IFNULL(v.price_set_id,0)=0;
|
||||
|
||||
INSERT INTO prc_price_set_product (
|
||||
price_type, psv_id, product_code, product_name, service_level, cargo_attr, dest_region,
|
||||
update_note, tax_mode, source_product_id, source_sheet, create_time
|
||||
)
|
||||
SELECT
|
||||
'REDLINE',
|
||||
v.psv_id,
|
||||
p.product_code,
|
||||
p.product_name,
|
||||
p.service_level,
|
||||
p.cargo_attr,
|
||||
p.dest_region,
|
||||
p.update_note,
|
||||
IFNULL(p.tax_mode, 'TAX_INCLUDED'),
|
||||
p.product_id,
|
||||
p.source_sheet,
|
||||
IFNULL(p.create_time, NOW())
|
||||
FROM redline_product p
|
||||
INNER JOIN prc_price_set_version v
|
||||
ON v.price_type = 'REDLINE' AND IFNULL(v.price_set_id,0)=0
|
||||
AND (
|
||||
(p.effective_date IS NULL AND v.effective_time IS NULL)
|
||||
OR p.effective_date = v.effective_time
|
||||
)
|
||||
WHERE IFNULL(p.is_del,'0') = '0'
|
||||
AND @redline_migrated = 0
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM prc_price_set_product x
|
||||
WHERE x.psv_id = v.psv_id AND x.product_code = p.product_code
|
||||
);
|
||||
|
||||
INSERT INTO tmp_redline_version_map (old_product_id, new_psv_id, new_psp_id)
|
||||
SELECT p.product_id, psp.psv_id, psp.psp_id
|
||||
FROM redline_product p
|
||||
INNER JOIN prc_price_set_product psp
|
||||
ON psp.price_type = 'REDLINE' AND psp.source_product_id = p.product_id;
|
||||
|
||||
INSERT INTO prc_price_set_detail (
|
||||
price_type, psv_id, psp_id, product_code, product_name, country_code, country_name,
|
||||
zone_id, zone_code, zone_name, weight_label, weight_min, weight_max, product_country_id,
|
||||
fv_value, fv_registration_fee, size_limit, last_mile, lead_time, round_mode,
|
||||
effective_date, expire_date, create_time
|
||||
)
|
||||
SELECT
|
||||
'REDLINE',
|
||||
m.new_psv_id,
|
||||
m.new_psp_id,
|
||||
c.product_code,
|
||||
p.product_name,
|
||||
c.country_code,
|
||||
c.country_name,
|
||||
c.zone_id,
|
||||
c.zone_code,
|
||||
c.zone_name,
|
||||
CASE
|
||||
WHEN c.weight_min IS NULL AND c.weight_max IS NULL THEN NULL
|
||||
ELSE CONCAT(
|
||||
IFNULL(TRIM(TRAILING '0' FROM TRIM(TRAILING '.' FROM CAST(c.weight_min AS CHAR))), ''),
|
||||
'<W≤',
|
||||
IFNULL(TRIM(TRAILING '0' FROM TRIM(TRAILING '.' FROM CAST(c.weight_max AS CHAR))), '')
|
||||
)
|
||||
END,
|
||||
c.weight_min,
|
||||
c.weight_max,
|
||||
c.detail_id,
|
||||
c.freight_price,
|
||||
c.registration_fee,
|
||||
c.size_limit,
|
||||
c.last_mile,
|
||||
c.lead_time,
|
||||
'HALF_UP',
|
||||
DATE(c.effective_date),
|
||||
DATE(c.expire_date),
|
||||
IFNULL(c.create_time, NOW())
|
||||
FROM redline_product_country c
|
||||
INNER JOIN tmp_redline_version_map m ON m.old_product_id = c.product_id
|
||||
INNER JOIN redline_product p ON p.product_id = c.product_id
|
||||
WHERE IFNULL(c.is_del,'0') = '0'
|
||||
AND @redline_migrated = 0
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM prc_price_set_detail d WHERE d.product_country_id = c.detail_id AND d.price_type = 'REDLINE'
|
||||
);
|
||||
|
||||
UPDATE prc_surcharge_rel r
|
||||
INNER JOIN tmp_redline_version_map m ON m.old_product_id = r.product_id
|
||||
SET r.product_id = m.new_psp_id
|
||||
WHERE r.price_type = 'REDLINE' AND IFNULL(r.is_del,'0') = '0'
|
||||
AND @redline_migrated = 0;
|
||||
|
||||
UPDATE prc_surcharge_rel r
|
||||
INNER JOIN prc_price_set_detail d ON d.price_type = 'REDLINE' AND d.product_country_id = r.detail_id
|
||||
SET r.detail_id = d.psd_id
|
||||
WHERE r.price_type = 'REDLINE' AND r.detail_id IS NOT NULL AND IFNULL(r.is_del,'0') = '0'
|
||||
AND @redline_migrated = 0;
|
||||
|
||||
-- Ensure SALES rows have price_type
|
||||
UPDATE prc_price_set_version SET price_type = 'SALES' WHERE price_set_id IS NOT NULL AND (price_type IS NULL OR price_type = '');
|
||||
UPDATE prc_price_set_product psp
|
||||
INNER JOIN prc_price_set_version v ON v.psv_id = psp.psv_id
|
||||
SET psp.price_type = 'SALES'
|
||||
WHERE v.price_type = 'SALES';
|
||||
UPDATE prc_price_set_detail d
|
||||
INNER JOIN prc_price_set_version v ON v.psv_id = d.psv_id
|
||||
SET d.price_type = 'SALES'
|
||||
WHERE v.price_type = 'SALES';
|
||||
|
||||
-- ========== 6) DROP old catalog tables ==========
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
DROP TABLE IF EXISTS product_country;
|
||||
DROP TABLE IF EXISTS redline_product_country;
|
||||
DROP TABLE IF EXISTS product;
|
||||
DROP TABLE IF EXISTS redline_product;
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 2) soft-delete is_del on product/detail (before drop pef_id)
|
||||
-- source: prc_price_set_is_del_alter.sql
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- Add soft-delete is_del to prc_price_set_product / prc_price_set_detail
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_product ADD COLUMN is_del char(1) NOT NULL DEFAULT ''0'' COMMENT ''是否删除 0未删除 1已删除'' AFTER pef_id, ADD KEY idx_psp_is_del (is_del)',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_product' AND COLUMN_NAME = 'is_del'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_detail ADD COLUMN is_del char(1) NOT NULL DEFAULT ''0'' COMMENT ''是否删除 0未删除 1已删除'' AFTER expire_date, ADD KEY idx_psd_is_del (is_del)',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_detail' AND COLUMN_NAME = 'is_del'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
UPDATE prc_price_set_product SET is_del = '0' WHERE is_del IS NULL OR is_del = '';
|
||||
UPDATE prc_price_set_detail SET is_del = '0' WHERE is_del IS NULL OR is_del = '';
|
||||
|
||||
-- Active-only unique: soft-deleted rows do not block re-insert of same product_code
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) > 0,
|
||||
'ALTER TABLE prc_price_set_product DROP INDEX uk_psp_psv_code',
|
||||
'SELECT 1')
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_product' AND INDEX_NAME = 'uk_psp_psv_code'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_product ADD COLUMN active_product_code varchar(20) GENERATED ALWAYS AS (CASE WHEN IFNULL(is_del,''0'') = ''0'' THEN product_code ELSE NULL END) STORED COMMENT ''未删除时等于product_code,用于唯一约束''',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_product' AND COLUMN_NAME = 'active_product_code'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_product ADD UNIQUE KEY uk_psp_psv_active_code (psv_id, active_product_code)',
|
||||
'SELECT 1')
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_product' AND INDEX_NAME = 'uk_psp_psv_active_code'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 3) product/detail effective_time expire_time status sync from version
|
||||
-- source: prc_price_set_product_effect_alter.sql
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- product effective/expire time and status; detail status; detail dates keep time
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_product ADD COLUMN effective_time datetime DEFAULT NULL COMMENT ''生效时间'' AFTER tax_mode',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_product' AND COLUMN_NAME = 'effective_time'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_product ADD COLUMN expire_time datetime DEFAULT NULL COMMENT ''失效时间(空=长期)'' AFTER effective_time',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_product' AND COLUMN_NAME = 'expire_time'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_product ADD COLUMN status char(1) NOT NULL DEFAULT ''0'' COMMENT ''状态 0草稿 3待生效 1已生效 2已失效'' AFTER expire_time',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_product' AND COLUMN_NAME = 'status'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- If status was added before expire_time, move status after expire_time when both exist
|
||||
SET @has_status := (
|
||||
SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_product' AND COLUMN_NAME = 'status'
|
||||
);
|
||||
SET @has_expire := (
|
||||
SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_product' AND COLUMN_NAME = 'expire_time'
|
||||
);
|
||||
SET @sql := (
|
||||
SELECT IF(@has_status > 0 AND @has_expire > 0,
|
||||
'ALTER TABLE prc_price_set_product MODIFY COLUMN status char(1) NOT NULL DEFAULT ''0'' COMMENT ''状态 0草稿 3待生效 1已生效 2已失效'' AFTER expire_time',
|
||||
'SELECT 1')
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
ALTER TABLE prc_price_set_detail
|
||||
MODIFY COLUMN effective_date datetime DEFAULT NULL COMMENT '生效时间',
|
||||
MODIFY COLUMN expire_date datetime DEFAULT NULL COMMENT '失效时间(空=长期)';
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_set_detail ADD COLUMN status char(1) NOT NULL DEFAULT ''0'' COMMENT ''状态 0草稿 3待生效 1已生效 2已失效'' AFTER expire_date',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_detail' AND COLUMN_NAME = 'status'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
UPDATE prc_price_set_product p
|
||||
INNER JOIN prc_price_set_version v ON v.psv_id = p.psv_id
|
||||
SET p.effective_time = v.effective_time,
|
||||
p.expire_time = v.expire_time,
|
||||
p.status = v.status
|
||||
WHERE p.price_type IN ('PRODUCT', 'REDLINE')
|
||||
AND v.price_set_id IS NULL;
|
||||
|
||||
UPDATE prc_price_set_detail d
|
||||
INNER JOIN prc_price_set_version v ON v.psv_id = d.psv_id
|
||||
SET d.effective_date = v.effective_time,
|
||||
d.expire_date = v.expire_time,
|
||||
d.status = v.status
|
||||
WHERE d.price_type IN ('PRODUCT', 'REDLINE')
|
||||
AND v.price_set_id IS NULL;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 4) create prc_price_excel_file
|
||||
-- source: prc_price_excel_file.sql
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- 导入价表 Excel 附件记录
|
||||
-- 关联:prc_price_excel_file.psv_id -> prc_price_set_version.psv_id
|
||||
-- ------------------------------------------------------------
|
||||
|
||||
CREATE TABLE IF NOT EXISTS prc_price_excel_file (
|
||||
pef_id bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
excel_type varchar(20) NOT NULL COMMENT '价表类型 PRODUCT/REDLINE/SALES',
|
||||
psv_id bigint(20) DEFAULT NULL COMMENT '价格版本id prc_price_set_version.psv_id',
|
||||
effective_time datetime NOT NULL COMMENT '生效时间',
|
||||
file_name varchar(255) NOT NULL COMMENT '文件原始名称',
|
||||
file_path varchar(500) NOT NULL COMMENT '文件存储路径',
|
||||
file_size bigint(20) DEFAULT 0 COMMENT '文件大小(字节)',
|
||||
content_type varchar(100) DEFAULT '' COMMENT 'MIME',
|
||||
file_extension varchar(20) DEFAULT '' COMMENT '扩展名',
|
||||
oss_id varchar(64) DEFAULT NULL,
|
||||
sheet_names varchar(1000) DEFAULT NULL,
|
||||
remark varchar(500) DEFAULT NULL,
|
||||
created_by varchar(64) DEFAULT '',
|
||||
create_time datetime DEFAULT NULL,
|
||||
updated_by varchar(64) DEFAULT '',
|
||||
update_time datetime DEFAULT NULL,
|
||||
PRIMARY KEY (pef_id),
|
||||
KEY idx_pef_type_eff (excel_type, effective_time),
|
||||
KEY idx_pef_psv (psv_id),
|
||||
KEY idx_pef_create_time (create_time)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='导入价表Excel附件';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 5) excel_file.psv_id backfill + drop product.pef_id
|
||||
-- source: prc_price_excel_psv_alter.sql
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- Move Excel attachment link: product.pef_id -> excel_file.psv_id
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_price_excel_file ADD COLUMN psv_id bigint(20) DEFAULT NULL COMMENT ''价格版本id prc_price_set_version.psv_id'' AFTER excel_type, ADD KEY idx_pef_psv (psv_id)',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_excel_file' AND COLUMN_NAME = 'psv_id'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @has_psp_pef := (
|
||||
SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_product' AND COLUMN_NAME = 'pef_id'
|
||||
);
|
||||
|
||||
SET @sql := IF(@has_psp_pef > 0,
|
||||
'UPDATE prc_price_excel_file f INNER JOIN (SELECT pef_id, MIN(psv_id) AS psv_id FROM prc_price_set_product WHERE pef_id IS NOT NULL GROUP BY pef_id) x ON x.pef_id = f.pef_id SET f.psv_id = IFNULL(f.psv_id, x.psv_id)',
|
||||
'SELECT 1');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) > 0,
|
||||
'ALTER TABLE prc_price_set_product DROP INDEX idx_psp_pef_id',
|
||||
'SELECT 1')
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_product' AND INDEX_NAME = 'idx_psp_pef_id'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql := (
|
||||
SELECT IF(COUNT(*) > 0,
|
||||
'ALTER TABLE prc_price_set_product DROP COLUMN pef_id',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_price_set_product' AND COLUMN_NAME = 'pef_id'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 6) order bill fail snapshot + income refund_status
|
||||
-- source: prc_order_bill_fail_snapshot_alter.sql
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- idempotent: order bill fail snapshot + income refund_status
|
||||
|
||||
SET @sql = (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_order_bill ADD COLUMN error_message varchar(1000) NULL COMMENT \'失败原因\' AFTER billing_fail_status',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_order_bill' AND COLUMN_NAME = 'error_message'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql = (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_order_bill ADD COLUMN order_status int NULL COMMENT \'上游订单状态\' AFTER order_time',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_order_bill' AND COLUMN_NAME = 'order_status'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql = (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_order_bill ADD COLUMN bl_pickup tinyint NULL COMMENT \'是否收货:0否/1是\' AFTER order_status',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_order_bill' AND COLUMN_NAME = 'bl_pickup'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql = (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_order_bill ADD COLUMN pickup_date datetime NULL COMMENT \'收货时间\' AFTER bl_pickup',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_order_bill' AND COLUMN_NAME = 'pickup_date'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @sql = (
|
||||
SELECT IF(COUNT(*) = 0,
|
||||
'ALTER TABLE prc_income_bill ADD COLUMN refund_status varchar(20) NOT NULL DEFAULT \'NONE\' COMMENT \'是否退货:NONE未退货/REFUNDED已退货\' AFTER income_total',
|
||||
'SELECT 1')
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'prc_income_bill' AND COLUMN_NAME = 'refund_status'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
ALTER TABLE prc_order_bill
|
||||
MODIFY COLUMN product_code varchar(20) NULL COMMENT '产品代码',
|
||||
MODIFY COLUMN weight decimal(10,3) NULL COMMENT '计费重量KG',
|
||||
MODIFY COLUMN billing_fail_status tinyint NOT NULL DEFAULT 0 COMMENT '计费失败状态:0成功/1未匹配产品/2未匹配国家/3未匹配重量段/4未绑定套餐/5无生效套餐版本/6已生成应收账单/7产品档案缺失/8未命中价格/9分区无价格/10邮编必填/11邮编未匹配分区/12上游订单不存在/13上游订单号为空/14上游客户为空/15上游产品为空/16上游重量无效/17计费时间为空/18退费订单无法解析/19客户代码为空/20客户已停用/21运费为空/22未知失败。仅0/1/2/3写入应收主表,仅0写入应收费用';
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 7) order bill query menu (2340/2341)
|
||||
-- source: order_bill_query_menu.sql
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- Move order source back under system monitor, add read-only order bill query under billing center
|
||||
|
||||
SET @monitorParent := (
|
||||
SELECT menu_id FROM sys_menu
|
||||
WHERE menu_type = 'M' AND (path = 'monitor' OR menu_name = '系统监控')
|
||||
ORDER BY menu_id
|
||||
LIMIT 1
|
||||
);
|
||||
|
||||
UPDATE sys_menu
|
||||
SET parent_id = @monitorParent,
|
||||
menu_name = '订单数据源',
|
||||
order_num = 9,
|
||||
path = 'orderSource',
|
||||
component = 'monitor/orderSource/index',
|
||||
route_name = 'OrderSource',
|
||||
visible = '0',
|
||||
status = '0',
|
||||
update_by = 'admin',
|
||||
update_time = sysdate()
|
||||
WHERE @monitorParent IS NOT NULL
|
||||
AND menu_type = 'C'
|
||||
AND (menu_id = 2325 OR perms = 'monitor:orderSource:list');
|
||||
|
||||
SET @billParent := (
|
||||
SELECT parent_id FROM sys_menu
|
||||
WHERE menu_type = 'C' AND component = 'price/billing/bill'
|
||||
ORDER BY menu_id
|
||||
LIMIT 1
|
||||
);
|
||||
|
||||
SET @orderBillMenuExists := (
|
||||
SELECT COUNT(*) FROM sys_menu WHERE menu_id = 2340 OR perms = 'price:orderBill:list'
|
||||
);
|
||||
|
||||
UPDATE sys_menu
|
||||
SET order_num = order_num + 1
|
||||
WHERE @billParent IS NOT NULL
|
||||
AND @orderBillMenuExists = 0
|
||||
AND parent_id = @billParent
|
||||
AND menu_type = 'C';
|
||||
|
||||
INSERT INTO sys_menu (
|
||||
menu_id, menu_name, parent_id, order_num, path, component, query, route_name,
|
||||
is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark
|
||||
)
|
||||
SELECT 2340, '订单列表查询', @billParent, 1,
|
||||
'orderBill', 'price/orderBill/index', '', 'OrderBillQuery',
|
||||
1, 0, 'C', '0', '0', 'price:orderBill:list', 'list', 'admin', sysdate(),
|
||||
'查询 prc_order_bill 全部订单,只读'
|
||||
FROM DUAL
|
||||
WHERE @billParent IS NOT NULL
|
||||
AND NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2340 OR perms = 'price:orderBill:list');
|
||||
|
||||
INSERT INTO sys_menu (
|
||||
menu_id, menu_name, parent_id, order_num, path, component,
|
||||
is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time
|
||||
)
|
||||
SELECT 2341, '查询', 2340, 1, '', NULL,
|
||||
1, 0, 'F', '0', '0', 'price:orderBill:list', '#', 'admin', sysdate()
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2341);
|
||||
|
||||
INSERT INTO sys_role_menu (role_id, menu_id)
|
||||
SELECT 1, m.menu_id
|
||||
FROM (SELECT 2340 AS menu_id UNION SELECT 2341) m
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM sys_role_menu rm WHERE rm.role_id = 1 AND rm.menu_id = m.menu_id
|
||||
);
|
||||
|
||||
INSERT INTO sys_role_menu (role_id, menu_id)
|
||||
SELECT DISTINCT rm.role_id, 2340
|
||||
FROM sys_role_menu rm
|
||||
JOIN sys_menu src ON src.menu_id = rm.menu_id
|
||||
WHERE src.menu_type = 'C' AND src.component = 'price/billing/bill'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM sys_role_menu x WHERE x.role_id = rm.role_id AND x.menu_id = 2340
|
||||
);
|
||||
|
||||
INSERT INTO sys_role_menu (role_id, menu_id)
|
||||
SELECT DISTINCT rm.role_id, 2341
|
||||
FROM sys_role_menu rm
|
||||
WHERE rm.menu_id = 2340
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM sys_role_menu x WHERE x.role_id = rm.role_id AND x.menu_id = 2341
|
||||
);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 8) order bill rebill menu (2342, depends on 2340)
|
||||
-- source: order_bill_rebill_menu.sql
|
||||
-- ---------------------------------------------------------------------------
|
||||
|
||||
-- Order list query: rebill button, same upstream sync as order data source
|
||||
|
||||
INSERT INTO sys_menu (
|
||||
menu_id, menu_name, parent_id, order_num, path, component,
|
||||
is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark
|
||||
)
|
||||
SELECT 2342, '重新计费', 2340, 2, '', NULL,
|
||||
1, 0, 'F', '0', '0', 'price:orderBill:rebill', '#', 'admin', sysdate(),
|
||||
'订单列表按单号或选中行重走上游计费'
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (SELECT 1 FROM sys_menu WHERE menu_id = 2342 OR perms = 'price:orderBill:rebill');
|
||||
|
||||
INSERT INTO sys_role_menu (role_id, menu_id)
|
||||
SELECT 1, 2342
|
||||
FROM DUAL
|
||||
WHERE NOT EXISTS (SELECT 1 FROM sys_role_menu WHERE role_id = 1 AND menu_id = 2342);
|
||||
|
||||
INSERT INTO sys_role_menu (role_id, menu_id)
|
||||
SELECT DISTINCT rm.role_id, 2342
|
||||
FROM sys_role_menu rm
|
||||
WHERE rm.menu_id = 2340
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM sys_role_menu x WHERE x.role_id = rm.role_id AND x.menu_id = 2342
|
||||
);
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
-- Price set viewer bind
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS prc_price_set_user (
|
||||
psu_id bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
price_set_id bigint(20) NOT NULL COMMENT '价格套餐id',
|
||||
user_id bigint(20) NOT NULL COMMENT '用户id',
|
||||
user_name varchar(64) NOT NULL DEFAULT '' COMMENT '登录账号',
|
||||
created_by varchar(64) DEFAULT '' COMMENT '创建人',
|
||||
create_time datetime DEFAULT NULL COMMENT '创建时间',
|
||||
PRIMARY KEY (psu_id),
|
||||
UNIQUE KEY uk_psu_set_user (price_set_id, user_id),
|
||||
KEY idx_psu_user (user_id),
|
||||
KEY idx_psu_set (price_set_id),
|
||||
CONSTRAINT fk_psu_set FOREIGN KEY (price_set_id) REFERENCES prc_price_set (price_set_id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='套餐可见用户绑定';
|
||||
@@ -412,3 +412,26 @@ export function delSetCustomer(ids) {
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function listSetViewer(query) {
|
||||
return request({
|
||||
url: '/price/set/viewer/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function addSetViewer(data) {
|
||||
return request({
|
||||
url: '/price/set/viewer',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function delSetViewer(ids) {
|
||||
return request({
|
||||
url: '/price/set/viewer/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -334,7 +334,7 @@ const columns = [
|
||||
{ label: '下单时间', prop: 'orderTime', align: 'center', width: 170, parseTime: true },
|
||||
{ label: '销售员', prop: 'belongSaler', minWidth: 100, showOverflowTooltip: true },
|
||||
{ label: '结算员', prop: 'settlementMan', minWidth: 100, showOverflowTooltip: true },
|
||||
// { label: '客服员', prop: 'serviceMan', minWidth: 100, showOverflowTooltip: true },
|
||||
{ label: '客服员', prop: 'serviceMan', minWidth: 100, showOverflowTooltip: true },
|
||||
{ label: '操作', prop: 'action', align: 'center', width: 240, fixed: 'right', slot: 'action', showInToolbar: false }
|
||||
]
|
||||
|
||||
|
||||
@@ -79,16 +79,6 @@
|
||||
<template #col-billingFailStatus="{ row }">
|
||||
<el-tag size="small" :type="billingFailTagType(row.billingFailStatus)">{{ billingFailLabel(row.billingFailStatus) }}</el-tag>
|
||||
</template>
|
||||
<template #col-action="{ row }">
|
||||
<el-button
|
||||
link
|
||||
type="warning"
|
||||
icon="Refresh"
|
||||
:loading="rebillingKey === row.billId"
|
||||
v-hasPermi="['price:orderBill:rebill']"
|
||||
@click="handleRebillOne(row)"
|
||||
>重新计费</el-button>
|
||||
</template>
|
||||
</basic-table>
|
||||
<order-source-sync-dialog ref="syncDialogRef" @success="onRebillSuccess" />
|
||||
<order-source-sync-log-drawer ref="logDrawerRef" />
|
||||
@@ -106,7 +96,6 @@ const tableRef = ref()
|
||||
const syncDialogRef = ref()
|
||||
const logDrawerRef = ref()
|
||||
const batchLoading = ref(false)
|
||||
const rebillingKey = ref(null)
|
||||
const tableHeight = ref(480)
|
||||
let tableResizeObserver = null
|
||||
|
||||
@@ -130,7 +119,7 @@ const columns = [
|
||||
{ label: '提货时间', prop: 'pickupDate', align: 'center', width: 170, parseTime: true },
|
||||
{ label: '销售员', prop: 'belongSaler', minWidth: 100, showOverflowTooltip: true },
|
||||
{ label: '结算员', prop: 'settlementMan', minWidth: 100, showOverflowTooltip: true },
|
||||
{ label: '操作', prop: 'action', align: 'center', width: 120, fixed: 'right', slot: 'action', showInToolbar: false }
|
||||
{ label: '客服员', prop: 'serviceMan', minWidth: 100, showOverflowTooltip: true }
|
||||
]
|
||||
|
||||
const orderStatusMap = {
|
||||
@@ -256,27 +245,6 @@ function toSyncRow(row) {
|
||||
}
|
||||
}
|
||||
|
||||
function handleRebillOne(row) {
|
||||
if (!toSyncRow(row).pickupDate) {
|
||||
ElMessage.warning('该订单没有计费时间,无法重新计费')
|
||||
return
|
||||
}
|
||||
ElMessageBox.confirm('确认重新计费该订单?', '二次确认', { type: 'warning' }).then(() => {
|
||||
rebillingKey.value = row.billId
|
||||
return syncOrderSourceSelected([toSyncRow(row)])
|
||||
}).then(res => {
|
||||
const data = (res && res.data) || {}
|
||||
if ((data.ok || 0) > 0 && !(data.fail || 0)) {
|
||||
ElMessage.success('重新计费成功')
|
||||
} else {
|
||||
const detail = data.details && data.details[0]
|
||||
ElMessage.error((detail && detail.errorMessage) || '重新计费失败')
|
||||
}
|
||||
tableRef.value?.refresh?.()
|
||||
}).catch(() => {}).finally(() => {
|
||||
rebillingKey.value = null
|
||||
})
|
||||
}
|
||||
|
||||
function handleBatchRebill(selection) {
|
||||
const rows = selection || []
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<set-section-card
|
||||
title="绑定用户"
|
||||
tone="orange"
|
||||
:count="viewers.length"
|
||||
sub="指定用户可查看本套餐(不受销售数据权限限制)"
|
||||
>
|
||||
<template #action>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="Plus"
|
||||
size="small"
|
||||
v-hasPermi="['price:set:edit']"
|
||||
@click="openBind"
|
||||
>绑定用户</el-button>
|
||||
</template>
|
||||
|
||||
<el-table :data="viewers" border class="user-table" empty-text="暂未绑定用户">
|
||||
<el-table-column label="账号" prop="userName" min-width="140" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span class="u-code">{{ row.userName }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="姓名" prop="nickName" min-width="140" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
{{ row.nickName || '-' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
v-hasPermi="['price:set:edit']"
|
||||
@click="onUnbind(row)"
|
||||
>解绑</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-dialog
|
||||
v-model="bindVisible"
|
||||
title="绑定用户"
|
||||
width="480px"
|
||||
append-to-body
|
||||
@closed="onClosed"
|
||||
>
|
||||
<el-form label-width="80px">
|
||||
<el-form-item label="用户" required>
|
||||
<el-select
|
||||
v-model="selectedUserIds"
|
||||
multiple
|
||||
filterable
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
placeholder="请选择用户"
|
||||
style="width: 100%"
|
||||
:loading="userLoading"
|
||||
>
|
||||
<el-option
|
||||
v-for="u in userOptions"
|
||||
:key="u.userId"
|
||||
:label="formatUser(u)"
|
||||
:value="u.userId"
|
||||
:disabled="u.status === '1' || boundUserIdSet.has(String(u.userId))"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="bindVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="submitting" @click="submitBind">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</set-section-card>
|
||||
</template>
|
||||
|
||||
<script setup name="SetUserTable">
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import SetSectionCard from './SetSectionCard.vue'
|
||||
import { useUsers } from '@/components/UserSelect/useUsers'
|
||||
import { addSetViewer, delSetViewer } from '@/api/price/set'
|
||||
|
||||
const props = defineProps({
|
||||
set: { type: Object, required: true }
|
||||
})
|
||||
const emit = defineEmits(['changed'])
|
||||
|
||||
const { userList, ensureUsers } = useUsers()
|
||||
const viewers = computed(() => props.set.viewers || [])
|
||||
const boundUserIdSet = computed(() => new Set(viewers.value.map(v => String(v.userId))))
|
||||
|
||||
const bindVisible = ref(false)
|
||||
const selectedUserIds = ref([])
|
||||
const userLoading = ref(false)
|
||||
const submitting = ref(false)
|
||||
const userOptions = computed(() => userList.value || [])
|
||||
|
||||
function formatUser(u) {
|
||||
const name = u.nickName || u.userName || ''
|
||||
return u.userName ? (name + ' (' + u.userName + ')') : name
|
||||
}
|
||||
|
||||
function openBind() {
|
||||
selectedUserIds.value = []
|
||||
bindVisible.value = true
|
||||
userLoading.value = true
|
||||
ensureUsers().finally(() => { userLoading.value = false })
|
||||
}
|
||||
|
||||
function onClosed() {
|
||||
selectedUserIds.value = []
|
||||
}
|
||||
|
||||
async function submitBind() {
|
||||
const ids = (selectedUserIds.value || []).filter(id => !boundUserIdSet.value.has(String(id)))
|
||||
if (!ids.length) {
|
||||
ElMessage.warning('请选择要绑定的用户')
|
||||
return
|
||||
}
|
||||
if (!props.set.priceSetId) {
|
||||
ElMessage.warning('套餐不存在')
|
||||
return
|
||||
}
|
||||
submitting.value = true
|
||||
let ok = 0
|
||||
let fail = 0
|
||||
try {
|
||||
for (const userId of ids) {
|
||||
try {
|
||||
await addSetViewer({ priceSetId: props.set.priceSetId, userId })
|
||||
ok++
|
||||
} catch (e) {
|
||||
fail++
|
||||
}
|
||||
}
|
||||
if (ok) ElMessage.success('绑定成功 ' + ok + (fail ? (',失败 ' + fail) : ''))
|
||||
else ElMessage.error('绑定失败')
|
||||
bindVisible.value = false
|
||||
emit('changed')
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function onUnbind(row) {
|
||||
if (!row || !row.psuId) return
|
||||
ElMessageBox.confirm(
|
||||
'确认解绑用户 ' + (row.nickName || row.userName || '') + ' ?',
|
||||
'解绑确认',
|
||||
{ type: 'warning' }
|
||||
).then(() => delSetViewer(row.psuId)).then(() => {
|
||||
ElMessage.success('已解绑')
|
||||
emit('changed')
|
||||
}).catch(() => {})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.user-table {
|
||||
border-radius: 6px;
|
||||
}
|
||||
.user-table :deep(th.el-table__cell) {
|
||||
background: #fafbfc;
|
||||
color: #606266;
|
||||
font-weight: 600;
|
||||
}
|
||||
.u-code {
|
||||
font-family: Consolas, Monaco, monospace;
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
}
|
||||
</style>
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
<set-customer-table :set="set" />
|
||||
|
||||
<set-user-table :set="set" @changed="load" />
|
||||
|
||||
<set-version-table
|
||||
v-model="currentPsvId"
|
||||
:versions="set.versions || []"
|
||||
@@ -80,6 +82,7 @@
|
||||
import SetDetailHeader from './components/detail/SetDetailHeader.vue'
|
||||
import SetBasicInfoCard from './components/detail/SetBasicInfoCard.vue'
|
||||
import SetCustomerTable from './components/detail/SetCustomerTable.vue'
|
||||
import SetUserTable from './components/detail/SetUserTable.vue'
|
||||
import SetVersionTable from './components/detail/SetVersionTable.vue'
|
||||
import SetVersionDetailDrawer from './components/detail/SetVersionDetailDrawer.vue'
|
||||
import SetVersionExcelFileDrawer from './components/detail/SetVersionExcelFileDrawer.vue'
|
||||
|
||||
Reference in New Issue
Block a user