139 lines
4.5 KiB
SQL
139 lines
4.5 KiB
SQL
-- Petstore Phase 0: create stable store-customer relationship master.
|
|
-- Target: MySQL. Run after 20260801_split_service_identity.sql.
|
|
-- One-time migration; back up the database before execution.
|
|
|
|
CREATE TABLE t_store_customer (
|
|
id BIGINT NOT NULL AUTO_INCREMENT,
|
|
store_id BIGINT NOT NULL COMMENT '门店 ID',
|
|
customer_user_id BIGINT NULL COMMENT '全局 customer 账号,留资客户可空',
|
|
phone VARCHAR(20) NULL COMMENT '本店最后确认的联系手机号',
|
|
display_name VARCHAR(64) NULL COMMENT '门店视角客户称呼',
|
|
source VARCHAR(32) NOT NULL COMMENT '首次来源',
|
|
first_contact_at DATETIME NULL COMMENT '首次接触时间',
|
|
last_contact_at DATETIME NULL COMMENT '最近接触时间',
|
|
create_time DATETIME NOT NULL,
|
|
update_time DATETIME NOT NULL,
|
|
deleted TINYINT(1) NOT NULL DEFAULT 0,
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY uk_store_customer_user (store_id, customer_user_id),
|
|
UNIQUE KEY uk_store_customer_phone (store_id, phone),
|
|
KEY idx_store_customer_active_update (store_id, deleted, update_time),
|
|
KEY idx_store_customer_last_contact (store_id, last_contact_at)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='门店客户关系主档';
|
|
|
|
-- 历史预约客户建档。旧数据无法精确确定首次是自助或代客,统一记为 appointment。
|
|
INSERT INTO t_store_customer (
|
|
store_id,
|
|
customer_user_id,
|
|
phone,
|
|
display_name,
|
|
source,
|
|
first_contact_at,
|
|
last_contact_at,
|
|
create_time,
|
|
update_time,
|
|
deleted
|
|
)
|
|
SELECT
|
|
a.store_id,
|
|
a.customer_user_id,
|
|
MAX(u.phone),
|
|
MAX(COALESCE(NULLIF(u.name, ''), NULLIF(u.username, ''), '客户')),
|
|
'appointment',
|
|
MIN(COALESCE(a.create_time, a.appointment_time, NOW())),
|
|
MAX(COALESCE(a.update_time, a.create_time, a.appointment_time, NOW())),
|
|
NOW(),
|
|
NOW(),
|
|
0
|
|
FROM t_appointment a
|
|
JOIN t_user u
|
|
ON u.id = a.customer_user_id
|
|
AND u.deleted = 0
|
|
AND u.role = 'customer'
|
|
WHERE a.deleted = 0
|
|
AND a.store_id IS NOT NULL
|
|
AND a.customer_user_id IS NOT NULL
|
|
GROUP BY a.store_id, a.customer_user_id;
|
|
|
|
-- 报告留资建档。若同店同手机已由预约建档,只更新最近接触时间并保留首次来源。
|
|
INSERT INTO t_store_customer (
|
|
store_id,
|
|
customer_user_id,
|
|
phone,
|
|
display_name,
|
|
source,
|
|
first_contact_at,
|
|
last_contact_at,
|
|
create_time,
|
|
update_time,
|
|
deleted
|
|
)
|
|
SELECT
|
|
l.store_id,
|
|
MAX(CASE WHEN u.role = 'customer' AND u.deleted = 0 THEN u.id ELSE NULL END),
|
|
l.phone,
|
|
MAX(CASE
|
|
WHEN u.role = 'customer' AND u.deleted = 0
|
|
THEN COALESCE(NULLIF(u.name, ''), NULLIF(u.username, ''), '留资客户')
|
|
ELSE '留资客户'
|
|
END),
|
|
'report_lead',
|
|
MIN(COALESCE(l.create_time, NOW())),
|
|
MAX(COALESCE(l.update_time, l.create_time, NOW())),
|
|
NOW(),
|
|
NOW(),
|
|
0
|
|
FROM t_report_lead l
|
|
LEFT JOIN t_user u
|
|
ON u.phone = l.phone
|
|
WHERE l.store_id IS NOT NULL
|
|
AND l.phone IS NOT NULL
|
|
AND l.phone <> ''
|
|
GROUP BY l.store_id, l.phone
|
|
ON DUPLICATE KEY UPDATE
|
|
customer_user_id = COALESCE(t_store_customer.customer_user_id, VALUES(customer_user_id)),
|
|
phone = COALESCE(t_store_customer.phone, VALUES(phone)),
|
|
display_name = CASE
|
|
WHEN t_store_customer.display_name IS NULL OR t_store_customer.display_name = ''
|
|
THEN VALUES(display_name)
|
|
ELSE t_store_customer.display_name
|
|
END,
|
|
first_contact_at = LEAST(
|
|
COALESCE(t_store_customer.first_contact_at, VALUES(first_contact_at)),
|
|
VALUES(first_contact_at)
|
|
),
|
|
last_contact_at = GREATEST(
|
|
COALESCE(t_store_customer.last_contact_at, VALUES(last_contact_at)),
|
|
VALUES(last_contact_at)
|
|
),
|
|
update_time = NOW(),
|
|
deleted = 0;
|
|
|
|
-- Verification queries. All three counts should be 0 before application release.
|
|
SELECT COUNT(*) AS appointments_without_store_customer
|
|
FROM t_appointment a
|
|
LEFT JOIN t_store_customer sc
|
|
ON sc.store_id = a.store_id
|
|
AND sc.customer_user_id = a.customer_user_id
|
|
AND sc.deleted = 0
|
|
WHERE a.deleted = 0
|
|
AND a.customer_user_id IS NOT NULL
|
|
AND sc.id IS NULL;
|
|
|
|
SELECT COUNT(*) AS leads_without_store_customer
|
|
FROM t_report_lead l
|
|
LEFT JOIN t_store_customer sc
|
|
ON sc.store_id = l.store_id
|
|
AND sc.phone = l.phone
|
|
AND sc.deleted = 0
|
|
WHERE l.store_id IS NOT NULL
|
|
AND l.phone IS NOT NULL
|
|
AND l.phone <> ''
|
|
AND sc.id IS NULL;
|
|
|
|
SELECT COUNT(*) AS store_customers_linked_to_non_customer
|
|
FROM t_store_customer sc
|
|
JOIN t_user u ON u.id = sc.customer_user_id
|
|
WHERE sc.deleted = 0
|
|
AND (u.deleted <> 0 OR u.role <> 'customer');
|