aonestar
.public
Tables
(current)
Columns
Constraints
Relationships
Orphan Tables
Anomalies
Routines
sp_change_door_credential
Parameters
Name
Type
Mode
i_register_id
integer
IN
i_from_room_id
integer
IN
i_user
text
IN (DEFAULT NULL)
Definition
DECLARE v_row intf_doorlock_logs%ROWTYPE; v_url text := fn_doorlock_api_url('staychange'); v_token text := nullif(btrim(fn_intf_param('DOORLOCK_PIN', 'api_key', '')), ''); v_pin_on boolean; v_qr_on boolean; v_has_pin boolean := false; v_had_qr boolean := false; v_changed boolean := false; -- แตะแถว credential จริงหรือยัง (PIN หรือ QR) v_reason text; -- เหตุที่ฝั่ง PIN ไม่ได้ทำอะไร (ไว้ debug) v_hotel text; v_to_room int; v_to_roomno text; v_from timestamp; v_until timestamp; v_payload jsonb; v_result jsonb; v_item jsonb; v_extra jsonb; v_qr jsonb; v_pin text; v_pwd_id text; v_booking_id int; v_guest_id int; v_arrival date; v_departure date; v_new_id int; v_room_moved boolean; v_pin_changed boolean := false; BEGIN v_pin_on := is_interface_active('DOORLOCK_PIN'); v_qr_on := is_interface_active('DOORLOCK_QR'); IF NOT v_pin_on AND NOT v_qr_on THEN RETURN jsonb_build_object('changed', false, 'reason', 'no door lock interface is active'); END IF; SELECT rg.room_id, rg.booking_id, rg.guest_id, rg.arrival, rg.departure INTO v_to_room, v_booking_id, v_guest_id, v_arrival, v_departure FROM registration rg WHERE rg.id = i_register_id; SELECT f.valid_from, f.valid_until INTO v_from, v_until FROM fn_doorlock_validity(i_register_id) AS f; v_room_moved := v_to_room IS DISTINCT FROM i_from_room_id; ---------------------------------------------------------------- ฝั่ง PIN (vendor staychange) IF v_pin_on THEN -- ไม่เคยมี PIN = แขกรายนี้ไม่ได้ใช้ door lock -> ไม่ควรจู่ ๆ ได้ PIN + อีเมลตอนย้ายห้อง SELECT * INTO v_row FROM intf_doorlock_logs WHERE register_id = i_register_id AND credential_type = 'PIN' AND status = 'P' ORDER BY log_time DESC LIMIT 1; v_has_pin := FOUND; IF NOT v_has_pin THEN v_reason := 'no active PIN'; ELSIF v_url IS NULL OR v_token IS NULL THEN v_reason := 'DOORLOCK_PIN is not configured'; ELSE v_hotel := coalesce(v_row.api_request->>'hotel_code', fn_prop_code()); v_to_roomno := fn_doorlock_roomno(v_to_room); -- room_from ต้องเป็นค่าที่ vendor รู้จักเป๊ะ ๆ -> อ่านจากแถวเดิมทั้งชุด ไม่คำนวณใหม่ v_payload := jsonb_build_object( 'hotel_code', v_hotel, 'room_from', jsonb_build_object( 'roomno', coalesce(v_row.api_request->>'roomno', fn_room_number(v_row.room_id)), 'effect', fn_doorlock_fmt_ts(v_row.valid_from), 'expire', fn_doorlock_fmt_ts(v_row.valid_until)), 'room_to', jsonb_build_object( 'roomno', v_to_roomno, 'effect', fn_doorlock_fmt_ts(v_from), 'expire', fn_doorlock_fmt_ts(v_until))); PERFORM http_set_curlopt('CURLOPT_TIMEOUT', '10'); v_result := sp_call_rpc(v_url, v_token, v_payload, 'DoorLock')::jsonb; -- v1.5: staychange คืน result_data เป็น object ตรง ๆ รูปแบบเดียวกับ addpasscode -- (ของเดิมเป็น result_data.list[] ซึ่งถูกลบไปแล้ว) v_item := v_result -> 'result_data'; -- ต้องมี keyboardPwd จริง ไม่ใช่แค่ result_data ไม่ null: response รูปแบบเก่า -- (result_data.list[]) หรือ response ที่ผิดรูป จะทำให้ v_pin เป็น NULL แล้ว -- ลงแถว 'P' ที่ไม่มีรหัส = credential ผีที่แขกใช้ไม่ได้แต่ระบบคิดว่าออกสำเร็จ IF coalesce(v_result->>'result_code', '') <> '0' OR v_item IS NULL OR v_item = 'null'::jsonb OR NULLIF(v_item->>'keyboardPwd', '') IS NULL THEN INSERT INTO intf_doorlock_logs ( register_id, room_id, booking_id, credential_type, valid_from, valid_until, status, api_request, api_response, log_user) VALUES (i_register_id, v_to_room, v_booking_id, 'PIN', v_from, v_until, 'E', v_payload, v_result, i_user); PERFORM sp_log_warning('sp_change_door_credential', 'staychange failed for register ' || i_register_id::text || ': ' || coalesce(v_result->>'result_msg', 'no keyboardPwd in result_data')); -- คืนทันทีเหมือนเดิม: PIN เพี้ยนอยู่ ยังไม่ควรออก QR ใบใหม่ + ส่งเมลบางส่วน RETURN jsonb_build_object('changed', false, 'reason', coalesce(v_result->>'result_msg', 'no keyboardPwd in result_data')); END IF; v_pin := v_item->>'keyboardPwd'; v_pwd_id := v_item->>'keyboardPwdId'; v_extra := jsonb_strip_nulls(jsonb_build_object( 'public_door', NULLIF(v_item -> 'public_door', '[]'::jsonb), 'sub_door', NULLIF(v_item -> 'sub_door', '[]'::jsonb))); v_extra := NULLIF(v_extra, '{}'::jsonb); v_pin_changed := v_pwd_id IS DISTINCT FROM v_row.credential_ref; IF v_pin_changed THEN -- vendor ออกใบใหม่ -> ใบเดิมใช้ไม่ได้แล้ว UPDATE intf_doorlock_logs SET status = 'R', revoke_time = now(), revoke_reason = 'STAYCHANGE' WHERE id = v_row.id; INSERT INTO intf_doorlock_logs ( register_id, room_id, booking_id, credential_type, pin_code, credential_ref, extra_doors, valid_from, valid_until, status, api_request, api_response, log_user) VALUES (i_register_id, v_to_room, v_booking_id, 'PIN', v_pin, v_pwd_id, v_extra, v_from, v_until, 'P', v_payload, v_result, i_user) RETURNING id INTO v_new_id; ELSE -- vendor reuse รหัสเดิม -> อัปเดตแถวเดิมให้ตรงห้อง/ช่วงเวลาใหม่ ไม่สร้างแถวซ้ำ UPDATE intf_doorlock_logs SET room_id = v_to_room, valid_from = v_from, valid_until = v_until, pin_code = coalesce(v_pin, pin_code), extra_doors = v_extra, api_response = v_result WHERE id = v_row.id; v_new_id := v_row.id; END IF; v_changed := true; END IF; END IF; ---------------------------------------------------------------- ฝั่ง QR (ไม่แตะ vendor) IF v_qr_on THEN v_had_qr := EXISTS (SELECT 1 FROM intf_doorlock_logs WHERE register_id = i_register_id AND credential_type = 'QR' AND status = 'P'); -- QR ผูกกับห้อง+ช่วงเวลา -> ย้ายห้อง/เปลี่ยนวันออกแล้วใบเดิมใช้ไม่ได้ ต้องออกใหม่ -- แต่ต้องเป็นแขกที่ใช้ door lock อยู่แล้วเท่านั้น (มี PIN active หรือมี QR active) IF v_has_pin OR v_had_qr THEN v_qr := sp_gen_door_qr(i_register_id, i_user); v_changed := v_changed OR v_qr IS NOT NULL; END IF; END IF; IF NOT v_changed THEN RETURN jsonb_build_object('changed', false, 'reason', coalesce(v_reason, 'no active credential to reissue')); END IF; -- ส่งเมลเฉพาะเมื่อมีของใหม่ให้แขกรู้จริง ๆ -- เปลี่ยนแค่วันออกโดยรหัสเดิม = ไม่มีอะไรใหม่ ไม่ต้องกวนแขก -- แต่ถ้าออก QR ใบใหม่ ใบเก่าถูก revoke ไปแล้ว แขกต้องได้ใบใหม่เสมอ IF (v_pin_changed OR v_room_moved OR v_qr IS NOT NULL) AND v_guest_id IS NOT NULL THEN BEGIN PERFORM sp_send_message_to_guest(v_guest_id, 'guest-welcome', jsonb_build_object( 'booking_id', v_booking_id, 'register_id', i_register_id, 'room_number', fn_room_number(v_to_room), 'arrival', to_char(v_arrival, 'DD/MM/YYYY'), 'departure', to_char(v_departure, 'DD/MM/YYYY'), 'pin_block', fn_doorlock_pin_block(fn_doorlock_credential(i_register_id)))); EXCEPTION WHEN OTHERS THEN PERFORM sp_log_warning('sp_change_door_credential', 'send guest-welcome failed for register ' || i_register_id::text || ': ' || SQLERRM); END; END IF; RETURN jsonb_build_object( 'changed', true, 'log_id', v_new_id, 'pin_code', v_pin, 'pin_changed', v_pin_changed, 'room_moved', v_room_moved, 'qr_reissued', v_qr IS NOT NULL); EXCEPTION WHEN OTHERS THEN -- fail-soft: ย้ายห้อง / เปลี่ยนวันออก ต้องสำเร็จต่อไปแม้ door lock ล่ม PERFORM sp_log_warning('sp_change_door_credential', 'register ' || coalesce(i_register_id::text, '?') || ': ' || SQLERRM); RETURN jsonb_build_object('changed', false, 'reason', SQLERRM); END