chore(cupang): 박스 입수량 박스명을 '쿠팡박스' 로 통일
운영 DB 일괄 변경 스크립트(cupang_box_rules_unify_box_name.sql) 추가. 기존 호수(2호/3호/6호)는 사라지지 않게 memo 뒤로 옮긴다 (예: "피킹비 750원 · 2호"). 시드 SQL 2개도 같은 규칙으로 맞춰, 재실행해도 호수 박스명이 되살아나지 않게 했다. 주의: 박스명은 박스 계산의 "자투리 혼합" 그룹 기준이라, 통일 후에는 2호/3호/6호 자투리가 한 박스에 섞여 계산된다(사용자 확인됨). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,20 +14,20 @@ BEGIN;
|
||||
INSERT INTO cupang_box_rules
|
||||
(product_code, product_name_snapshot, box_name, units_per_box, memo, active)
|
||||
VALUES
|
||||
('MS-1001', '미라네 1호 세트', '쿠팡 2호', 8, '피킹비 750원', TRUE),
|
||||
('MS-1002', '미라네 2호 세트', '쿠팡 2호', 8, '피킹비 1100원', TRUE),
|
||||
('MS-1003', '미라네 3호 세트', '쿠팡 2호', 8, '피킹비 1200원', TRUE),
|
||||
('MS-1004', '미라네 4호 세트', '쿠팡 2호', 8, '피킹비 1000원', TRUE),
|
||||
('MS-1005', '미라네 5호 세트', '쿠팡 2호', 8, '피킹비 650원', TRUE),
|
||||
('MS-1006', '미라네 6호 세트', '쿠팡 2호', 8, '피킹비 750원', TRUE),
|
||||
('MS-1007', '미라네 7호 세트', '쿠팡 2호', 8, '피킹비 850원', TRUE),
|
||||
('MS-9812', '황토 김치통 1호세트', '쿠팡 2호', 8, '피킹비 750원', TRUE),
|
||||
('MS-9813', '황토 김치통 2호세트', '쿠팡 2호', 8, '피킹비 650원', TRUE),
|
||||
('MS-9814', '황토 김치통 3호세트', '쿠팡 2호', 8, '피킹비 750원', TRUE),
|
||||
('MS-9815', '황토 김치통 4호세트', '쿠팡 3호', 2, '피킹비 850원', TRUE),
|
||||
('MS-9816', '황토 김치통 5호세트', '쿠팡 3호', 2, '피킹비 900원', TRUE),
|
||||
('MS-9817', '황토 김치통 6호세트', '쿠팡 6호', 1, '피킹비 1000원', TRUE),
|
||||
('MS-9818', '황토 김치통 7호세트', '쿠팡 6호', 1, '피킹비 1100원', TRUE)
|
||||
('MS-1001', '미라네 1호 세트', '쿠팡박스', 8, '피킹비 750원 · 2호', TRUE),
|
||||
('MS-1002', '미라네 2호 세트', '쿠팡박스', 8, '피킹비 1100원 · 2호', TRUE),
|
||||
('MS-1003', '미라네 3호 세트', '쿠팡박스', 8, '피킹비 1200원 · 2호', TRUE),
|
||||
('MS-1004', '미라네 4호 세트', '쿠팡박스', 8, '피킹비 1000원 · 2호', TRUE),
|
||||
('MS-1005', '미라네 5호 세트', '쿠팡박스', 8, '피킹비 650원 · 2호', TRUE),
|
||||
('MS-1006', '미라네 6호 세트', '쿠팡박스', 8, '피킹비 750원 · 2호', TRUE),
|
||||
('MS-1007', '미라네 7호 세트', '쿠팡박스', 8, '피킹비 850원 · 2호', TRUE),
|
||||
('MS-9812', '황토 김치통 1호세트', '쿠팡박스', 8, '피킹비 750원 · 2호', TRUE),
|
||||
('MS-9813', '황토 김치통 2호세트', '쿠팡박스', 8, '피킹비 650원 · 2호', TRUE),
|
||||
('MS-9814', '황토 김치통 3호세트', '쿠팡박스', 8, '피킹비 750원 · 2호', TRUE),
|
||||
('MS-9815', '황토 김치통 4호세트', '쿠팡박스', 2, '피킹비 850원 · 3호', TRUE),
|
||||
('MS-9816', '황토 김치통 5호세트', '쿠팡박스', 2, '피킹비 900원 · 3호', TRUE),
|
||||
('MS-9817', '황토 김치통 6호세트', '쿠팡박스', 1, '피킹비 1000원 · 6호', TRUE),
|
||||
('MS-9818', '황토 김치통 7호세트', '쿠팡박스', 1, '피킹비 1100원 · 6호', TRUE)
|
||||
ON CONFLICT (product_code) DO UPDATE
|
||||
SET product_name_snapshot = EXCLUDED.product_name_snapshot,
|
||||
box_name = EXCLUDED.box_name,
|
||||
|
||||
@@ -15,41 +15,42 @@
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
BEGIN;
|
||||
|
||||
-- box_no: 원자료의 박스 호수. 박스명은 '쿠팡박스' 로 통일하고 호수는 memo 에 남긴다.
|
||||
CREATE TEMP TABLE _seed2 (
|
||||
product_name TEXT,
|
||||
picking_fee INTEGER,
|
||||
units_per_box INTEGER,
|
||||
box_name TEXT
|
||||
box_no TEXT
|
||||
) ON COMMIT DROP;
|
||||
|
||||
INSERT INTO _seed2 (product_name, picking_fee, units_per_box, box_name) VALUES
|
||||
('미라클통 550x4', 700, 40, '쿠팡 2호'),
|
||||
('미라클통 550x6', 700, 30, '쿠팡 2호'),
|
||||
('미라클통 750x5', 700, 30, '쿠팡 2호'),
|
||||
('미라클통 950x4', 700, 24, '쿠팡 2호'),
|
||||
('미라클통 950x6', 700, 18, '쿠팡 2호'),
|
||||
('미라클통 1800x4', 700, 16, '쿠팡 2호'),
|
||||
('미라클통 1800x6', 700, 14, '쿠팡 2호'),
|
||||
('미라클통 2200x4', 700, 14, '쿠팡 2호'),
|
||||
('미라클통 2200x6', 700, 10, '쿠팡 2호'),
|
||||
('미라클통 3200x4', 700, 10, '쿠팡 2호'),
|
||||
('빠져락 x1', 500, 35, '쿠팡 2호'),
|
||||
('빠져락 x3', 580, 8, '쿠팡 2호'),
|
||||
('빠져락 x5', 780, 8, '쿠팡 2호'),
|
||||
('미라클백 2.5L', 500, 30, '쿠팡 5호'),
|
||||
('미라클백 6.0L', 500, 23, '쿠팡 6호'),
|
||||
('멀티 5,000ml x2', 700, 8, '쿠팡 2호'),
|
||||
('멀티 5,000ml x4', 680, 2, '쿠팡 3호'),
|
||||
('점보 7,000ml x2', 700, 6, '쿠팡 2호'),
|
||||
('점보 황토 7,000ml x2', 700, 6, '쿠팡 2호');
|
||||
INSERT INTO _seed2 (product_name, picking_fee, units_per_box, box_no) VALUES
|
||||
('미라클통 550x4', 700, 40, '2호'),
|
||||
('미라클통 550x6', 700, 30, '2호'),
|
||||
('미라클통 750x5', 700, 30, '2호'),
|
||||
('미라클통 950x4', 700, 24, '2호'),
|
||||
('미라클통 950x6', 700, 18, '2호'),
|
||||
('미라클통 1800x4', 700, 16, '2호'),
|
||||
('미라클통 1800x6', 700, 14, '2호'),
|
||||
('미라클통 2200x4', 700, 14, '2호'),
|
||||
('미라클통 2200x6', 700, 10, '2호'),
|
||||
('미라클통 3200x4', 700, 10, '2호'),
|
||||
('빠져락 x1', 500, 35, '2호'),
|
||||
('빠져락 x3', 580, 8, '2호'),
|
||||
('빠져락 x5', 780, 8, '2호'),
|
||||
('미라클백 2.5L', 500, 30, '5호'),
|
||||
('미라클백 6.0L', 500, 23, '6호'),
|
||||
('멀티 5,000ml x2', 700, 8, '2호'),
|
||||
('멀티 5,000ml x4', 680, 2, '3호'),
|
||||
('점보 7,000ml x2', 700, 6, '2호'),
|
||||
('점보 황토 7,000ml x2', 700, 6, '2호');
|
||||
|
||||
INSERT INTO cupang_box_rules
|
||||
(product_code, product_name_snapshot, box_name, units_per_box, memo, active)
|
||||
SELECT p.product_code,
|
||||
p.product_name,
|
||||
s.box_name,
|
||||
'쿠팡박스',
|
||||
s.units_per_box,
|
||||
'피킹비 ' || s.picking_fee || '원',
|
||||
'피킹비 ' || s.picking_fee || '원 · ' || s.box_no,
|
||||
TRUE
|
||||
FROM _seed2 s
|
||||
JOIN cupang_products p
|
||||
@@ -65,7 +66,7 @@ SET product_name_snapshot = EXCLUDED.product_name_snapshot,
|
||||
-- 카탈로그에 없어 입력되지 않은 제품 (수기 추가 후 재실행 대상)
|
||||
SELECT s.product_name AS "카탈로그_미등록_제품명",
|
||||
s.units_per_box AS "입수량",
|
||||
s.box_name AS "박스이름"
|
||||
s.box_no AS "박스호수"
|
||||
FROM _seed2 s
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM cupang_products p
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
-- 쿠팡 밀크런 — 박스 입수량 규칙의 박스명을 '쿠팡박스' 로 통일 (cupang_db)
|
||||
--
|
||||
-- 실행 전 반드시 백업:
|
||||
-- docker exec postgres-db pg_dump -U postgres -d cupang_db -t cupang_box_rules \
|
||||
-- > ~/backup/cupang_box_rules_$(date +%F_%H%M).sql
|
||||
--
|
||||
-- 실행:
|
||||
-- docker exec -i postgres-db psql -U postgres -d cupang_db \
|
||||
-- < /opt/www/main/scripts/sql/cupang_box_rules_unify_box_name.sql
|
||||
--
|
||||
-- 주의: 박스명은 "자투리 혼합 박스" 계산에서 같은 박스끼리만 섞는 기준이다.
|
||||
-- 통일 후에는 2호/3호/6호 자투리가 한 박스에 섞여 계산된다.
|
||||
-- 기존 호수(2호/3호/6호)는 없어지지 않게 memo 뒤에 옮겨 적는다.
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
BEGIN;
|
||||
|
||||
-- 변경 전 상태
|
||||
SELECT box_name AS "변경전_박스명", count(*) AS "건수"
|
||||
FROM cupang_box_rules
|
||||
GROUP BY box_name
|
||||
ORDER BY box_name;
|
||||
|
||||
UPDATE cupang_box_rules
|
||||
SET memo = btrim(
|
||||
coalesce(memo, '')
|
||||
|| CASE WHEN coalesce(memo, '') = '' THEN '' ELSE ' · ' END
|
||||
|| regexp_replace(box_name, '^쿠팡\s*', '')
|
||||
),
|
||||
box_name = '쿠팡박스'
|
||||
WHERE box_name IS DISTINCT FROM '쿠팡박스';
|
||||
|
||||
COMMIT;
|
||||
|
||||
-- 변경 후 확인 (박스명이 '쿠팡박스' 한 줄이어야 정상)
|
||||
SELECT box_name AS "변경후_박스명", count(*) AS "건수"
|
||||
FROM cupang_box_rules
|
||||
GROUP BY box_name
|
||||
ORDER BY box_name;
|
||||
|
||||
SELECT product_code, product_name_snapshot, box_name, units_per_box, memo
|
||||
FROM cupang_box_rules
|
||||
ORDER BY product_code;
|
||||
@@ -0,0 +1,63 @@
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
-- itemcode_db: itemcode_ro 읽기 권한 재발 방지 (이벤트 트리거)
|
||||
--
|
||||
-- 증상: 말레이시아/쿠팡/dispatch 에서 세트 BOM "누락"·콤보 미분해·
|
||||
-- 사방넷 출고 A열 빈칸. 진짜 원인은 데이터가 아니라 권한 —
|
||||
-- "permission denied for table set_components(또는 single_items,
|
||||
-- set_items)". itemcode_db 를 재import/재생성하면 itemcode_ro
|
||||
-- GRANT 가 통째로 소실돼 반복 재발(2026-06-16/22/23/26/30, 07-01).
|
||||
--
|
||||
-- main-app 은 itemcode_db 를 읽기 전용(itemcode_ro)으로만 쓴다.
|
||||
-- import 절차는 다른 앱(상품코드 마스터)에 있어 이 저장소가 못 건드림.
|
||||
-- 그래서 import 절차와 무관하게, 테이블이 생길 때마다 postgres 가
|
||||
-- 자동으로 itemcode_ro 에 SELECT 를 부여하도록 이벤트 트리거를 건다.
|
||||
-- pg_restore 로 테이블이 drop→recreate 돼도 트리거가 즉시 재부여.
|
||||
--
|
||||
-- 실행(서버, superuser):
|
||||
-- docker exec -i postgres-db psql -U postgres -d itemcode_db \
|
||||
-- -f - < scripts/sql/itemcode_db_grant_ro_autotrigger.sql
|
||||
-- 또는 파일 내용을 heredoc 으로 붙여넣기.
|
||||
--
|
||||
-- ⚠ 이벤트 트리거는 "테이블 drop→recreate"(pg_restore --clean, TRUNCATE
|
||||
-- 아님) 케이스를 자동 커버. 만약 import 가 DROP DATABASE 후 재생성이면
|
||||
-- 트리거 자체도 사라지므로, DB 재생성 직후 이 스크립트를 1회 다시 실행.
|
||||
--
|
||||
-- superuser(postgres)로 실행. 멱등.
|
||||
-- ════════════════════════════════════════════════════════════
|
||||
|
||||
-- 1) 지금 존재하는 테이블에 즉시 부여 (현재고 복구)
|
||||
GRANT SELECT ON ALL TABLES IN SCHEMA public TO itemcode_ro;
|
||||
|
||||
-- 2) 소유자(king) 기준 default privileges — king 이 만드는 신규 테이블 자동
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE king IN SCHEMA public
|
||||
GRANT SELECT ON TABLES TO itemcode_ro;
|
||||
|
||||
-- 3) 이벤트 트리거 — 소유자·생성 방식 무관하게 CREATE TABLE 마다 자동 GRANT
|
||||
CREATE OR REPLACE FUNCTION public.grant_select_to_itemcode_ro()
|
||||
RETURNS event_trigger
|
||||
LANGUAGE plpgsql
|
||||
SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
obj record;
|
||||
BEGIN
|
||||
FOR obj IN
|
||||
SELECT object_identity
|
||||
FROM pg_event_trigger_ddl_commands()
|
||||
WHERE command_tag = 'CREATE TABLE'
|
||||
AND schema_name = 'public'
|
||||
LOOP
|
||||
EXECUTE format('GRANT SELECT ON %s TO itemcode_ro', obj.object_identity);
|
||||
END LOOP;
|
||||
END;
|
||||
$$;
|
||||
|
||||
DROP EVENT TRIGGER IF EXISTS trg_grant_select_to_itemcode_ro;
|
||||
CREATE EVENT TRIGGER trg_grant_select_to_itemcode_ro
|
||||
ON ddl_command_end
|
||||
WHEN TAG IN ('CREATE TABLE')
|
||||
EXECUTE FUNCTION public.grant_select_to_itemcode_ro();
|
||||
|
||||
-- 확인:
|
||||
-- \dp set_components → itemcode_ro=r/king 표시되면 OK
|
||||
-- \dy → trg_grant_select_to_itemcode_ro 등록 확인
|
||||
Reference in New Issue
Block a user