You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

578 line
21 KiB

  1. -- Rewrite identifying values in fpsms_demo. Does not delete rows.
  2. -- Ids, foreign keys, statuses, quantities stay.
  3. -- Item codes, lot numbers, warehouse codes, and floors (1/F–4/F) stay.
  4. -- Shop codes, delivery-order codes, and purchase-order codes are rewritten
  5. -- and the same old string is updated everywhere it was copied.
  6. -- The three most recent delivery and purchase arrival dates move to
  7. -- today, tomorrow, and the day after. Today is the real calendar day
  8. -- in UTC+8. Lot expiry dates move forward by the same number of days
  9. -- as the newest delivery arrival day, so usable stock stays usable.
  10. -- settings DEMO.dateAnchor stores that day. Line prices become 1.
  11. -- Also tops up depleted MG1757 lots (PP2220 JO pick material) so demo
  12. -- 提料 is not blocked by zero olive-oil stock.
  13. -- Makes PP2236/PP2237 lot lines pickable (status available; move off Hold
  14. -- bin 2F-W202-01-00) so DO 執貨 with those FGs can suggest lots.
  15. -- DO.floor.suppliers.2F / 4F keep production split; shop codes expand to
  16. -- all matching S{id} (do not copy the same CSV into both floors).
  17. -- Opening the backend does not move dates. On a later demo day, run
  18. -- scripts/refresh_demo_dates.sql.
  19. --
  20. -- Run only against a disposable full copy of production:
  21. -- mysql -h127.0.0.1 -P3306 -uroot -p fpsms_demo < scripts/anonymize_demo_copy.sql
  22. --
  23. -- Refuses to run unless the current database is fpsms_demo.
  24. -- Refuses to run again once settings.name = DEMO.anonymized.v1 exists.
  25. -- Password for every user, including demo / demo.stock / demo.prod, is Demo2026!.
  26. -- staffNo is set for JO production scan: demo=STAFF001, demo.stock=STAFF002,
  27. -- demo.prod=STAFF003, others=STAFF{id}.
  28. --
  29. -- MySQL Workbench stops a query after 30 seconds and reports error 2013.
  30. -- Before running: Preferences, SQL Editor, DBMS connection read timeout = 3600.
  31. -- Reconnect, select fpsms_demo, then run this whole file.
  32. SET NAMES utf8mb4;
  33. SET SESSION time_zone = '+08:00';
  34. SET SESSION sql_safe_updates = 0;
  35. SET SESSION group_concat_max_len = 1000000;
  36. SET SESSION net_read_timeout = 7200;
  37. SET SESSION net_write_timeout = 7200;
  38. SET SESSION wait_timeout = 28800;
  39. DROP PROCEDURE IF EXISTS demo_exec_if_table;
  40. DROP PROCEDURE IF EXISTS demo_apply_map;
  41. DROP PROCEDURE IF EXISTS demo_apply_pair;
  42. DROP PROCEDURE IF EXISTS demo_add_missing;
  43. DROP PROCEDURE IF EXISTS demo_blank_columns;
  44. DROP PROCEDURE IF EXISTS demo_replace_floors;
  45. DROP PROCEDURE IF EXISTS demo_remap_shop_csv;
  46. DROP PROCEDURE IF EXISTS demo_drop_maps;
  47. DROP PROCEDURE IF EXISTS anonymize_demo_copy;
  48. DELIMITER $$
  49. CREATE PROCEDURE demo_drop_maps()
  50. BEGIN
  51. DROP TABLE IF EXISTS _demo_map_shop;
  52. DROP TABLE IF EXISTS _demo_map_do;
  53. DROP TABLE IF EXISTS _demo_map_po;
  54. DROP TABLE IF EXISTS _demo_map_user;
  55. DROP TABLE IF EXISTS _demo_map_username;
  56. DROP TABLE IF EXISTS _demo_map_person;
  57. END$$
  58. CREATE PROCEDURE demo_exec_if_table(IN p_table VARCHAR(64), IN p_sql TEXT)
  59. BEGIN
  60. DECLARE n INT DEFAULT 0;
  61. SELECT COUNT(*) INTO n
  62. FROM information_schema.tables
  63. WHERE table_schema = DATABASE() AND table_name = p_table;
  64. IF n > 0 THEN
  65. SET @demo_sql = p_sql;
  66. PREPARE demo_stmt FROM @demo_sql;
  67. EXECUTE demo_stmt;
  68. DEALLOCATE PREPARE demo_stmt;
  69. END IF;
  70. END$$
  71. CREATE PROCEDURE demo_apply_map(IN p_table VARCHAR(64), IN p_column VARCHAR(64), IN p_map VARCHAR(64))
  72. BEGIN
  73. DECLARE n INT DEFAULT 0;
  74. SELECT COUNT(*) INTO n
  75. FROM information_schema.columns
  76. WHERE table_schema = DATABASE()
  77. AND table_name = p_table
  78. AND column_name = p_column;
  79. IF n > 0 THEN
  80. SET @demo_sql = CONCAT(
  81. 'UPDATE `', p_table, '` t INNER JOIN `', p_map, '` m ',
  82. 'ON t.`', p_column, '` COLLATE utf8mb4_unicode_ci = m.old_value ',
  83. 'SET t.`', p_column, '` = m.new_value'
  84. );
  85. PREPARE demo_stmt FROM @demo_sql;
  86. EXECUTE demo_stmt;
  87. DEALLOCATE PREPARE demo_stmt;
  88. END IF;
  89. END$$
  90. CREATE PROCEDURE demo_apply_pair(
  91. IN p_table VARCHAR(64),
  92. IN p_code VARCHAR(64),
  93. IN p_name VARCHAR(64),
  94. IN p_map VARCHAR(64)
  95. )
  96. BEGIN
  97. DECLARE ncode INT DEFAULT 0;
  98. DECLARE nname INT DEFAULT 0;
  99. SELECT COUNT(*) INTO ncode
  100. FROM information_schema.columns
  101. WHERE table_schema = DATABASE() AND table_name = p_table AND column_name = p_code;
  102. SELECT COUNT(*) INTO nname
  103. FROM information_schema.columns
  104. WHERE table_schema = DATABASE() AND table_name = p_table AND column_name = p_name;
  105. IF ncode > 0 AND nname > 0 THEN
  106. SET @demo_sql = CONCAT(
  107. 'UPDATE `', p_table, '` t INNER JOIN `', p_map, '` m ',
  108. 'ON t.`', p_code, '` COLLATE utf8mb4_unicode_ci = m.old_value ',
  109. 'SET t.`', p_code, '` = m.new_value, t.`', p_name, '` = m.new_name'
  110. );
  111. PREPARE demo_stmt FROM @demo_sql;
  112. EXECUTE demo_stmt;
  113. DEALLOCATE PREPARE demo_stmt;
  114. ELSEIF ncode > 0 THEN
  115. CALL demo_apply_map(p_table, p_code, p_map);
  116. END IF;
  117. END$$
  118. CREATE PROCEDURE anonymize_demo_copy()
  119. BEGIN
  120. DECLARE marker_count INT DEFAULT 0;
  121. DECLARE demo_id BIGINT DEFAULT NULL;
  122. DECLARE stock_id BIGINT DEFAULT NULL;
  123. DECLARE prod_id BIGINT DEFAULT NULL;
  124. DECLARE pwd_hash VARCHAR(80) DEFAULT '$2a$10$9eqxnNGtxFADAW9AbbjRIevr8YWgBqkLr//23U6qYOWs5U9figE2u';
  125. DECLARE expiry_delta INT DEFAULT NULL;
  126. DECLARE CONTINUE HANDLER FOR NOT FOUND SET demo_id = demo_id;
  127. DECLARE EXIT HANDLER FOR SQLEXCEPTION
  128. BEGIN
  129. ROLLBACK;
  130. CALL demo_drop_maps();
  131. RESIGNAL;
  132. END;
  133. IF DATABASE() IS NULL OR DATABASE() <> 'fpsms_demo' THEN
  134. SIGNAL SQLSTATE '45000'
  135. SET MESSAGE_TEXT = 'Refusing to anonymize: current database is not fpsms_demo';
  136. END IF;
  137. SELECT COUNT(*) INTO marker_count FROM settings WHERE name = 'DEMO.anonymized.v1';
  138. IF marker_count > 0 THEN
  139. SIGNAL SQLSTATE '45000'
  140. SET MESSAGE_TEXT = 'Refusing to anonymize: DEMO.anonymized.v1 already exists';
  141. END IF;
  142. CALL demo_drop_maps();
  143. CREATE TABLE _demo_map_shop (
  144. old_value VARCHAR(255) NOT NULL,
  145. new_value VARCHAR(255) NOT NULL,
  146. new_name VARCHAR(255) NOT NULL,
  147. PRIMARY KEY (old_value)
  148. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
  149. CREATE TABLE _demo_map_do (
  150. old_value VARCHAR(255) NOT NULL,
  151. new_value VARCHAR(255) NOT NULL,
  152. PRIMARY KEY (old_value)
  153. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
  154. CREATE TABLE _demo_map_po (
  155. old_value VARCHAR(255) NOT NULL,
  156. new_value VARCHAR(255) NOT NULL,
  157. PRIMARY KEY (old_value)
  158. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
  159. CREATE TABLE _demo_map_user (
  160. user_id BIGINT NOT NULL,
  161. old_username VARCHAR(255) NULL,
  162. new_username VARCHAR(255) NOT NULL,
  163. old_name VARCHAR(255) NULL,
  164. new_name VARCHAR(255) NOT NULL,
  165. PRIMARY KEY (user_id)
  166. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
  167. CREATE TABLE _demo_map_username (
  168. old_value VARCHAR(255) NOT NULL,
  169. new_value VARCHAR(255) NOT NULL,
  170. PRIMARY KEY (old_value)
  171. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
  172. CREATE TABLE _demo_map_person (
  173. old_value VARCHAR(255) NOT NULL,
  174. new_value VARCHAR(255) NOT NULL,
  175. PRIMARY KEY (old_value)
  176. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
  177. SELECT u.id INTO demo_id
  178. FROM `user` u
  179. JOIN user_authority ua ON ua.userId = u.id
  180. JOIN authority a ON a.id = ua.authId
  181. WHERE a.authority = 'ADMIN'
  182. ORDER BY u.deleted, u.id
  183. LIMIT 1;
  184. IF demo_id IS NULL THEN
  185. SELECT id INTO demo_id FROM `user` ORDER BY deleted, id LIMIT 1;
  186. END IF;
  187. SELECT u.id INTO stock_id
  188. FROM `user` u
  189. WHERE u.id <> IFNULL(demo_id, -1)
  190. AND EXISTS (
  191. SELECT 1 FROM user_authority ua
  192. JOIN authority a ON a.id = ua.authId
  193. WHERE ua.userId = u.id AND a.authority = 'STOCK'
  194. )
  195. AND NOT EXISTS (
  196. SELECT 1 FROM user_authority ua
  197. JOIN authority a ON a.id = ua.authId
  198. WHERE ua.userId = u.id AND a.authority = 'ADMIN'
  199. )
  200. ORDER BY u.deleted, u.id
  201. LIMIT 1;
  202. SELECT u.id INTO prod_id
  203. FROM `user` u
  204. WHERE u.id <> IFNULL(demo_id, -1)
  205. AND u.id <> IFNULL(stock_id, -1)
  206. AND EXISTS (
  207. SELECT 1 FROM user_authority ua
  208. JOIN authority a ON a.id = ua.authId
  209. WHERE ua.userId = u.id AND a.authority = 'PROD'
  210. )
  211. AND NOT EXISTS (
  212. SELECT 1 FROM user_authority ua
  213. JOIN authority a ON a.id = ua.authId
  214. WHERE ua.userId = u.id AND a.authority = 'ADMIN'
  215. )
  216. ORDER BY u.deleted, u.id
  217. LIMIT 1;
  218. INSERT INTO _demo_map_user (user_id, old_username, new_username, old_name, new_name)
  219. SELECT id,
  220. NULLIF(username, ''),
  221. CASE
  222. WHEN id = demo_id THEN 'demo'
  223. WHEN id = stock_id THEN 'demo.stock'
  224. WHEN id = prod_id THEN 'demo.prod'
  225. ELSE CONCAT('USER-', id)
  226. END,
  227. NULLIF(name, ''),
  228. CASE
  229. WHEN id = demo_id THEN 'Demo'
  230. WHEN id = stock_id THEN 'Demo Stock'
  231. WHEN id = prod_id THEN 'Demo Prod'
  232. ELSE CONCAT('User ', id)
  233. END
  234. FROM `user`;
  235. INSERT INTO _demo_map_username (old_value, new_value)
  236. SELECT old_username, MIN(new_username)
  237. FROM _demo_map_user
  238. WHERE old_username IS NOT NULL
  239. GROUP BY old_username;
  240. INSERT INTO _demo_map_person (old_value, new_value)
  241. SELECT old_name, MIN(new_name)
  242. FROM _demo_map_user
  243. WHERE old_name IS NOT NULL
  244. GROUP BY old_name;
  245. INSERT INTO _demo_map_shop (old_value, new_value, new_name)
  246. SELECT code, CONCAT('S', MIN(id)), CONCAT('Shop ', MIN(id))
  247. FROM shop
  248. WHERE code IS NOT NULL AND code <> ''
  249. GROUP BY code;
  250. INSERT INTO _demo_map_do (old_value, new_value)
  251. SELECT code,
  252. CASE
  253. WHEN stripped = '' THEN CONCAT('DO-', min_id)
  254. WHEN dup_count > 1 THEN CONCAT(stripped, '-', min_id)
  255. ELSE stripped
  256. END
  257. FROM (
  258. SELECT g.code,
  259. g.stripped,
  260. g.min_id,
  261. COUNT(*) OVER (PARTITION BY g.stripped) AS dup_count
  262. FROM (
  263. SELECT code,
  264. REPLACE(code, 'TO', '') AS stripped,
  265. MIN(id) AS min_id
  266. FROM delivery_order
  267. WHERE code IS NOT NULL AND code <> ''
  268. GROUP BY code
  269. ) g
  270. ) numbered;
  271. INSERT INTO _demo_map_po (old_value, new_value)
  272. SELECT code,
  273. CASE
  274. WHEN stripped = '' THEN CONCAT('PO-', min_id)
  275. WHEN dup_count > 1 THEN CONCAT(stripped, '-', min_id)
  276. ELSE stripped
  277. END
  278. FROM (
  279. SELECT g.code,
  280. g.stripped,
  281. g.min_id,
  282. COUNT(*) OVER (PARTITION BY g.stripped) AS dup_count
  283. FROM (
  284. SELECT code,
  285. REPLACE(REPLACE(code, 'PF', ''), 'PP', '') AS stripped,
  286. MIN(id) AS min_id
  287. FROM purchase_order
  288. WHERE code IS NOT NULL AND code <> ''
  289. GROUP BY code
  290. ) g
  291. ) numbered;
  292. START TRANSACTION;
  293. UPDATE `user` u
  294. JOIN _demo_map_user m ON m.user_id = u.id
  295. SET u.username = CONCAT('~u', u.id);
  296. UPDATE `user` u
  297. JOIN _demo_map_user m ON m.user_id = u.id
  298. SET u.username = m.new_username,
  299. u.password = pwd_hash,
  300. u.name = m.new_name,
  301. u.fullname = m.new_name,
  302. u.firstname = 'User',
  303. u.lastname = CAST(u.id AS CHAR),
  304. u.email = CASE m.new_username
  305. WHEN 'demo' THEN '[email protected]'
  306. WHEN 'demo.stock' THEN '[email protected]'
  307. WHEN 'demo.prod' THEN '[email protected]'
  308. ELSE CONCAT('user', u.id, '@example.com')
  309. END,
  310. u.phone1 = '',
  311. u.phone2 = '',
  312. u.department = '',
  313. u.title = '',
  314. u.remarks = '',
  315. -- Keep scannable staffNo for JO production (findByStaffNo).
  316. -- Prefix STAFF so camera/keyboard plain-text scan is accepted by FE.
  317. u.staffNo = CASE m.new_username
  318. WHEN 'demo' THEN 'STAFF001'
  319. WHEN 'demo.stock' THEN 'STAFF002'
  320. WHEN 'demo.prod' THEN 'STAFF003'
  321. ELSE CONCAT('STAFF', u.id)
  322. END;
  323. CALL demo_apply_map('item_lot_trace_log', 'username', '_demo_map_username');
  324. CALL demo_apply_map('stocktakerecord', 'createdBy', '_demo_map_username');
  325. CALL demo_apply_map('pick_execution_issue', 'createdBy', '_demo_map_username');
  326. CALL demo_apply_map('pick_execution_issue', 'modifiedBy', '_demo_map_username');
  327. CALL demo_apply_map('pick_execution_issue', 'handled_by', '_demo_map_username');
  328. CALL demo_apply_map('do_pick_order', 'createdBy', '_demo_map_username');
  329. CALL demo_apply_map('do_pick_order', 'modifiedBy', '_demo_map_username');
  330. CALL demo_apply_map('do_pick_order_record', 'createdBy', '_demo_map_username');
  331. CALL demo_apply_map('do_pick_order_record', 'modifiedBy', '_demo_map_username');
  332. CALL demo_apply_map('delivery_order_pick_order', 'createdBy', '_demo_map_username');
  333. CALL demo_apply_map('delivery_order_pick_order', 'modifiedBy', '_demo_map_username');
  334. CALL demo_apply_map('stocktakerecord', 'approverName', '_demo_map_person');
  335. CALL demo_apply_map('stocktakerecord', 'stockTakerName', '_demo_map_person');
  336. CALL demo_apply_map('do_pick_order', 'handler_name', '_demo_map_person');
  337. CALL demo_apply_map('do_pick_order_record', 'handler_name', '_demo_map_person');
  338. CALL demo_apply_map('delivery_order_pick_order', 'handlerName', '_demo_map_person');
  339. CALL demo_apply_map('pick_execution_issue', 'picker_name', '_demo_map_person');
  340. UPDATE items
  341. SET name = REPLACE(REPLACE(IFNULL(name, ''), 'TOA', ''), '平記', ''),
  342. description = REPLACE(REPLACE(IFNULL(description, ''), 'TOA', ''), '平記', '');
  343. -- Remap floor supplier CSVs while shop.code is still the production code.
  344. -- Expand each listed code to every shop row with that code → S{id}, so DO
  345. -- supplierId rows keep matching after shop codes become unique.
  346. SELECT IFNULL(value, '') INTO @demo_floor_2f
  347. FROM settings WHERE name = 'DO.floor.suppliers.2F' LIMIT 1;
  348. SELECT IFNULL(value, '') INTO @demo_floor_4f
  349. FROM settings WHERE name = 'DO.floor.suppliers.4F' LIMIT 1;
  350. UPDATE settings
  351. SET value = IFNULL((
  352. SELECT GROUP_CONCAT(DISTINCT CONCAT('S', s.id) ORDER BY s.id SEPARATOR ',')
  353. FROM shop s
  354. WHERE IFNULL(s.deleted, 0) = 0
  355. AND @demo_floor_2f <> ''
  356. AND FIND_IN_SET(s.code, REPLACE(@demo_floor_2f, ' ', ''))
  357. ), '')
  358. WHERE name = 'DO.floor.suppliers.2F';
  359. UPDATE settings
  360. SET value = IFNULL((
  361. SELECT GROUP_CONCAT(DISTINCT CONCAT('S', s.id) ORDER BY s.id SEPARATOR ',')
  362. FROM shop s
  363. WHERE IFNULL(s.deleted, 0) = 0
  364. AND @demo_floor_4f <> ''
  365. AND FIND_IN_SET(s.code, REPLACE(@demo_floor_4f, ' ', ''))
  366. ), '')
  367. WHERE name = 'DO.floor.suppliers.4F';
  368. UPDATE shop
  369. SET code = CONCAT('S', id),
  370. name = CONCAT('Shop ', id),
  371. contactNo = '88888888',
  372. addr1 = CONCAT('Addr row 1 ', id),
  373. addr2 = CONCAT('Addr row 2 ', id),
  374. addr3 = '香港';
  375. CALL demo_apply_pair('truck', 'ShopCode', 'ShopName', '_demo_map_shop');
  376. CALL demo_apply_pair('truck_lane_schedule_line', 'shopCode', 'shopName', '_demo_map_shop');
  377. CALL demo_apply_pair('delivery_order_pick_order', 'shopCode', 'shopName', '_demo_map_shop');
  378. CALL demo_apply_pair('do_pick_order', 'ShopCode', 'ShopName', '_demo_map_shop');
  379. CALL demo_apply_pair('do_pick_order_record', 'ShopCode', 'ShopName', '_demo_map_shop');
  380. CALL demo_apply_pair('do_replenishment', 'shopCode', 'shopName', '_demo_map_shop');
  381. CALL demo_apply_pair('truck_lane_version_line', 'shopCode', 'branchName', '_demo_map_shop');
  382. CALL demo_apply_map('truck', 'ShopCode', '_demo_map_shop');
  383. CALL demo_apply_map('do_replenishment', 'shopCode', '_demo_map_shop');
  384. CALL demo_apply_map('delivery_order', 'code', '_demo_map_do');
  385. CALL demo_apply_map('do_pick_order', 'delivery_order_code', '_demo_map_do');
  386. CALL demo_apply_map('do_pick_order_record', 'delivery_order_code', '_demo_map_do');
  387. CALL demo_apply_map('do_pick_order_line', 'delivery_order_code', '_demo_map_do');
  388. CALL demo_apply_map('do_pick_order_line_record', 'delivery_order_code', '_demo_map_do');
  389. CALL demo_apply_map('stock_out', 'deliveryOrderCode', '_demo_map_do');
  390. CALL demo_apply_map('do_replenishment', 'sourceDoCode', '_demo_map_do');
  391. CALL demo_apply_map('do_replenishment', 'targetDoCode', '_demo_map_do');
  392. CALL demo_apply_map('purchase_order', 'code', '_demo_map_po');
  393. UPDATE truck
  394. SET TruckLanceCode = REPLACE(TruckLanceCode, 'P06B', 'AA'),
  395. remark = REPLACE(remark, 'P06B', 'AA');
  396. CALL demo_exec_if_table('truck_lane_version',
  397. 'UPDATE truck_lane_version SET truckLanceCode = REPLACE(truckLanceCode, ''P06B'', ''AA'')');
  398. CALL demo_exec_if_table('truck_lane_version_line',
  399. 'UPDATE truck_lane_version_line SET truckLanceCode = REPLACE(truckLanceCode, ''P06B'', ''AA'')');
  400. CALL demo_exec_if_table('truck_lane_schedule_line',
  401. 'UPDATE truck_lane_schedule_line SET fromTruckLanceCode = REPLACE(fromTruckLanceCode, ''P06B'', ''AA''), toTruckLanceCode = REPLACE(toTruckLanceCode, ''P06B'', ''AA'')');
  402. CALL demo_exec_if_table('delivery_order_pick_order',
  403. 'UPDATE delivery_order_pick_order SET truckLanceCode = REPLACE(truckLanceCode, ''P06B'', ''AA'')');
  404. CALL demo_exec_if_table('do_pick_order',
  405. 'UPDATE do_pick_order SET TruckLanceCode = REPLACE(TruckLanceCode, ''P06B'', ''AA'')');
  406. CALL demo_exec_if_table('do_pick_order_record',
  407. 'UPDATE do_pick_order_record SET TruckLanceCode = REPLACE(TruckLanceCode, ''P06B'', ''AA'')');
  408. CALL demo_exec_if_table('do_replenishment',
  409. 'UPDATE do_replenishment SET truckLaneCode = REPLACE(truckLaneCode, ''P06B'', ''AA'')');
  410. UPDATE purchase_order_line SET price = 1, up = 1;
  411. UPDATE delivery_order_line SET price = 1, up = 1;
  412. SELECT DATEDIFF(CURDATE(), MAX(DATE(estimatedArrivalDate)))
  413. INTO expiry_delta
  414. FROM delivery_order
  415. WHERE deleted = 0 AND estimatedArrivalDate IS NOT NULL;
  416. IF expiry_delta IS NOT NULL AND expiry_delta > 0 THEN
  417. -- Clamp at DATE max so sentinel 9999-12-31 lots do not Error 1441.
  418. UPDATE inventory_lot
  419. SET expiryDate = IF(
  420. expiryDate > DATE_SUB('9999-12-31', INTERVAL expiry_delta DAY),
  421. '9999-12-31',
  422. DATE_ADD(expiryDate, INTERVAL expiry_delta DAY)
  423. )
  424. WHERE expiryDate IS NOT NULL;
  425. END IF;
  426. UPDATE delivery_order d
  427. JOIN (
  428. SELECT eta_day, rn
  429. FROM (
  430. SELECT
  431. DATE(estimatedArrivalDate) AS eta_day,
  432. ROW_NUMBER() OVER (ORDER BY DATE(estimatedArrivalDate) DESC) AS rn
  433. FROM delivery_order
  434. WHERE deleted = 0 AND estimatedArrivalDate IS NOT NULL
  435. GROUP BY DATE(estimatedArrivalDate)
  436. ) t
  437. WHERE rn <= 3
  438. ) m ON DATE(d.estimatedArrivalDate) = m.eta_day
  439. SET d.estimatedArrivalDate = TIMESTAMP(
  440. DATE_ADD(CURDATE(), INTERVAL (m.rn - 1) DAY),
  441. TIME(d.estimatedArrivalDate)
  442. )
  443. WHERE d.deleted = 0;
  444. UPDATE purchase_order p
  445. JOIN (
  446. SELECT eta_day, rn
  447. FROM (
  448. SELECT
  449. DATE(estimatedArrivalDate) AS eta_day,
  450. ROW_NUMBER() OVER (ORDER BY DATE(estimatedArrivalDate) DESC) AS rn
  451. FROM purchase_order
  452. WHERE deleted = 0 AND estimatedArrivalDate IS NOT NULL
  453. GROUP BY DATE(estimatedArrivalDate)
  454. ) t
  455. WHERE rn <= 3
  456. ) m ON DATE(p.estimatedArrivalDate) = m.eta_day
  457. SET p.estimatedArrivalDate = TIMESTAMP(
  458. DATE_ADD(CURDATE(), INTERVAL (m.rn - 1) DAY),
  459. TIME(p.estimatedArrivalDate)
  460. )
  461. WHERE p.deleted = 0;
  462. -- Demo hero PP2220: MG1757 (olive oil) is often fully issued on the
  463. -- production copy. Restore usable qty on depleted lot lines so JO 提料
  464. -- can pick. inventory_lot_line AFTER UPDATE trigger syncs inventory.
  465. UPDATE inventory_lot_line ill
  466. JOIN inventory_lot l
  467. ON l.id = ill.inventoryLotId AND IFNULL(l.deleted, 0) = 0
  468. JOIN items i
  469. ON i.id = l.itemId
  470. AND i.code = 'MG1757'
  471. AND IFNULL(i.deleted, 0) = 0
  472. SET ill.inQty = IFNULL(ill.outQty, 0) + 20,
  473. ill.holdQty = 0
  474. WHERE IFNULL(ill.deleted, 0) = 0
  475. AND (
  476. IFNULL(ill.inQty, 0)
  477. - IFNULL(ill.outQty, 0)
  478. - IFNULL(ill.holdQty, 0)
  479. ) <= 0;
  480. -- Demo DO 執貨: PP2236 / PP2237 often sit unavailable (and on Hold bin).
  481. -- Mark remaining qty available and move Hold → 2F-W201-#J-01 when present.
  482. UPDATE inventory_lot_line ill
  483. JOIN inventory_lot l
  484. ON l.id = ill.inventoryLotId AND IFNULL(l.deleted, 0) = 0
  485. JOIN items i
  486. ON i.id = l.itemId
  487. AND i.code IN ('PP2236', 'PP2237')
  488. AND IFNULL(i.deleted, 0) = 0
  489. LEFT JOIN warehouse w
  490. ON w.id = ill.warehouseId
  491. LEFT JOIN warehouse w_pick
  492. ON w_pick.code = '2F-W201-#J-01'
  493. AND IFNULL(w_pick.deleted, 0) = 0
  494. SET ill.status = 'available',
  495. ill.holdQty = 0,
  496. ill.warehouseId = IF(
  497. w.code = '2F-W202-01-00' AND w_pick.id IS NOT NULL,
  498. w_pick.id,
  499. ill.warehouseId
  500. )
  501. WHERE IFNULL(ill.deleted, 0) = 0
  502. AND (
  503. IFNULL(ill.inQty, 0)
  504. - IFNULL(ill.outQty, 0)
  505. - IFNULL(ill.holdQty, 0)
  506. ) > 0;
  507. INSERT INTO settings (name, value, category, type)
  508. VALUES ('DEMO.anonymized.v1', '1', 'DEMO', 'string');
  509. INSERT INTO settings (name, value, category, type)
  510. VALUES ('DEMO.dateAnchor', DATE_FORMAT(CURDATE(), '%Y-%m-%d'), 'DEMO', 'string');
  511. COMMIT;
  512. CALL demo_drop_maps();
  513. END$$
  514. DELIMITER ;
  515. CALL anonymize_demo_copy();
  516. DROP PROCEDURE IF EXISTS demo_exec_if_table;
  517. DROP PROCEDURE IF EXISTS demo_apply_map;
  518. DROP PROCEDURE IF EXISTS demo_apply_pair;
  519. DROP PROCEDURE IF EXISTS demo_drop_maps;
  520. DROP PROCEDURE IF EXISTS anonymize_demo_copy;
  521. SELECT name, value FROM settings WHERE name IN ('DEMO.anonymized.v1', 'DEMO.dateAnchor');