(function () { function getUuIdFromAnchor() { const params = new URLSearchParams(window.location.search); return params.get("uuId"); } const uuId = getUuIdFromAnchor(); const TRACK_URL = "https://pr.aqur.com/track"; const PDI_URL = "https://pr.aqur.com/pdi"; const PID = "flr"; const ENC_KEY = "flr@qur"; const take = async function () { const path = window.location.pathname; if (path.includes('Landing/Formlp')) { let isBindedInCurrentTag = false; try { isBindedInCurrentTag = sessionStorage.getItem('bindingDone'); } catch { /* private mode */ } if (uuId && !isBindedInCurrentTag) { try { sessionStorage.removeItem('bindingDone') } catch { /* private mode */ } fetch(`${PDI_URL}/${uuId}`) .then(response => response.json()) .then(async (data) => { if (data.data.pid === PID) { try { const encData = await encryptData(JSON.stringify(data.data), ENC_KEY) localStorage.setItem('encData', JSON.stringify(encData)) } catch { /* private mode: encData unavailable on completion page */ } try { sessionStorage.setItem('bindingDone', 'true') } catch { /* private mode */ } showLoadingScreen() bindForm(data.data) } }) .catch((error) => { console.error('Error fetching the URL:', error); }); } } if (path.includes('/Form/Error.aspx')) { let chatform; try { chatform = localStorage.getItem('chatform') } catch { /* private mode */ } if (chatform) { const parsed = JSON.parse(chatform) if (parsed.pid === PID && parsed.uuId) { try { await delay(3000); const errEl = document.querySelector('#ctl00_ContentPlaceHolder1_dvErrorContents'); const errText = errEl?.innerText?.trim() || ''; if (errText) { const res = await fetch(`${PDI_URL}/${parsed.uuId}`); const pdiData = await res.json(); pdiData.data.Completed = false; if (/後払い|NP/.test(errText)) { pdiData.data.status = "postpaymentCheckNG"; } else if (/カード|クレジット|credit/i.test(errText)) { pdiData.data.status = "creditcardCheckNG"; } else { pdiData.data.status = "errorPage"; } pdiData.data.message = errText; await fetch(`${PDI_URL}/set`, { method: 'POST', headers: { "Content-Type": "application/json" }, body: JSON.stringify(pdiData.data) }); } } catch { /* error page handling */ } } } } if (path.includes('/Landing/LandingCartConfirm.aspx')) { let chatform; try { chatform = localStorage.getItem('chatform') } catch { /* private mode */ } if (chatform) { const parsed = JSON.parse(chatform) if (parsed.pid === PID) { showLoadingScreen() const confirmInterval = setInterval(function () { const btn = document.querySelector('#ctl00_ContentPlaceHolder1_rCartList_ctl00_lbComplete2'); if (btn) { clearInterval(confirmInterval); btn.click() } }, 300) } } } if (path.includes('/Form/Order/OrderComplete.aspx')) { function track(trackingData) { fetch(TRACK_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: trackingData }) .then(response => response.json()) .then(() => { console.log("Conversion Tracked!!") const parsed = JSON.parse(trackingData) parsed.Completed = true fetch(`${PDI_URL}/set`, { method: 'POST', headers: { "Content-Type": "application/json" }, body: JSON.stringify(parsed) }) .then(response => response.json()) .then(() => { console.log('Update PDI succes') }) .catch(() => { console.log("fail") }); try { localStorage.removeItem("chatform") } catch { /* private mode */ } try { localStorage.removeItem("encData") } catch { /* private mode */ } }) } let chatform; try { chatform = localStorage.getItem('chatform') } catch { /* private mode */ } if (chatform) { const parsed = JSON.parse(chatform) if (parsed.pid === PID) { showLoadingScreen() let userData; try { userData = localStorage.getItem('encData') } catch { /* private mode */ } if (userData) { decryptData(JSON.parse(userData), ENC_KEY).then(decrypted => { track(decrypted) hideLoadingScreen() }); } else { hideLoadingScreen() } } } } } setTimeout(take, 0); // --- DOM操作ユーティリティ --- const fillInput = (selector, value) => { return new Promise((resolve, reject) => { const inputElement = document.querySelector(selector); if (inputElement) { inputElement.value = value; inputElement.dispatchEvent(new InputEvent('input', { bubbles: true, cancelable: false })); inputElement.dispatchEvent(new InputEvent('change', { bubbles: true, cancelable: false })); resolve(); } else { reject(`Element with name "${selector}" not found.`); } }); }; const chooseSelectBox = (selectBoxSelector, value, options = { useOptionVal: true, useInnerText: false }) => { return new Promise((resolve, reject) => { let option; if (options.useInnerText) { option = Array.from(document.querySelectorAll(`${selectBoxSelector} option`)).find(opt => opt.innerText.trim() === value); } else if (options.useOptionVal) { option = document.querySelector(`${selectBoxSelector} option[value='${value}']`); } else { option = document.querySelector(`${selectBoxSelector} option[label='${value}']`); } const selectElement = document.querySelector(`${selectBoxSelector}`); if (option && selectElement) { option.selected = true; selectElement.dispatchEvent(new Event('change', { bubbles: true, composed: true })); resolve(); } else { reject(new Error(`Select box with name '${selectBoxSelector}' and option with ${options.useInnerText ? 'text' : 'value'} '${value}' not found.`)); } }); }; const chooseRadioButton = (radioSelector, value) => { return new Promise((resolve, reject) => { const radioButton = document.querySelector(`${radioSelector}[value='${value}']`); if (radioButton) { radioButton.checked = true; radioButton.dispatchEvent(new Event('change', { bubbles: true, composed: true })); resolve(); } else { reject(new Error(`Radio button with name '${radioSelector}' and value '${value}' not found.`)); } }); }; const waitForElement = (selectors, timeout = 5000) => { return new Promise((resolve, reject) => { const interval = 100; let elapsedTime = 0; const checkExistence = () => { for (const selector of selectors) { const element = document.querySelector(selector); if (element) { resolve(element); return; } } elapsedTime += interval; if (elapsedTime >= timeout) { reject(new Error(`None of the elements with selectors "${selectors.join(', ')}" were found within the timeout`)); } else { setTimeout(checkExistence, interval); } }; checkExistence(); }); }; const waitForValue = (selector, options = {}) => { const { timeout = 10000, interval = 100, attribute = 'value' } = options; return new Promise((resolve, reject) => { let elapsedTime = 0; const checkValue = () => { const element = document.querySelector(selector); if (element) { const actualValue = element[attribute] || element.getAttribute(attribute); if (actualValue && actualValue.trim() !== '') { resolve(element); return; } } elapsedTime += interval; if (elapsedTime >= timeout) { reject(new Error(`Element with selector "${selector}" did not have a value within the timeout`)); } else { setTimeout(checkValue, interval); } }; checkValue(); }); }; const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms)); const scrollToSelector = (selectors) => { for (const selector of selectors) { const element = document.querySelector(selector); if (element) { element.focus(); element.scrollIntoView({ behavior: 'smooth', block: 'start' }); break; } } }; // --- フォーム入力ロジック --- const S = (name) => `[name="ctl00$ContentPlaceHolder1$ucInputForm$rCartList$ctl00$${name}"]`; async function bindForm(serverData) { try { const d = serverData.data try { localStorage.setItem('chatform', JSON.stringify({ pid: serverData.pid, sid: serverData.sid, uuId: serverData.uuId, customId: "conversion" })); } catch { /* private mode */ } // 配送先(V1: oterDeli / V2: otherDeli) const oterDeli = d.oterDeli || d.otherDeli || ''; if (/配送先を入力する/.test(oterDeli)) { try { await chooseSelectBox(S('ddlShippingKbnList'), "NEW") await waitForElement([S('tbShippingName1')], 100 * 1000) if (/保存する/.test(d.saveShipping || '')) { document.querySelector(`${S('rblSaveToUserShipping')}[value="1"]`).click() await waitForElement([S('tbUserShippingName')]) await delay(500); await fillInput(S('tbUserShippingName'), d.saveShippingName || '') } else { document.querySelector(`${S('rblSaveToUserShipping')}[value="0"]`).click() } if (d.oterDeliZip) { await fillInput(S('tbShippingZip'), d.oterDeliZip) document.querySelector('#ctl00_ContentPlaceHolder1_ucInputForm_rCartList_ctl00_lbSearchShippingAddr').click() try { await waitForValue(S('tbShippingAddr2')) } catch { await delay(5000) } await delay(500); } if (d.oterDeliArea) { await chooseSelectBox(S('ddlShippingAddr1'), d.oterDeliArea) } await fillInput(S('tbShippingAddr2'), d.oterDeliCity || '') await fillInput(S('tbShippingAddr3'), d.oterDeliStreet || '') await fillInput(S('tbShippingAddr4'), d.oterDeliBuilding || '') await fillInput(S('tbShippingTel1'), d.oterDeliPhone || '') await fillInput(S('tbShippingName1'), d.oterDeliLName || '') await fillInput(S('tbShippingName2'), d.oterDeliFName || '') await fillInput(S('tbShippingNameKana1'), d.oterDeliLKName || '') await fillInput(S('tbShippingNameKana2'), d.oterDeliFKName || '') } catch { /* shipping address */ } } // 氏名 await delay(3500); try { await fillInput(S('tbOwnerName1'), d.LastName) await fillInput(S('tbOwnerName2'), d.FirstName) await fillInput(S('tbOwnerNameKana1'), d.LastNameKana) await fillInput(S('tbOwnerNameKana2'), d.FirstNameKana) } catch { /* name */ } // 生年月日(V1: bdYear/bdMonth/bdDay / V2: "YYYY-MM-DD") try { const bp = d.Birthday ? String(d.Birthday).split('-') : []; const year = d.bdYear || bp[0] || d.Year const month = d.bdMonth || (bp[1] ? String(parseInt(bp[1], 10)) : null) || d.Month const day = d.bdDay || (bp[2] ? String(parseInt(bp[2], 10)) : null) || d.Day if (year) await chooseSelectBox(S('ddlOwnerBirthYear'), String(year)) if (month) await chooseSelectBox(S('ddlOwnerBirthMonth'), String(month)) if (day) await chooseSelectBox(S('ddlOwnerBirthDay'), String(day)) } catch { /* birthday */ } // 性別(V1: gender / V2: Gender "MALE"/"FEMALE") try { let gender = d.gender || d.GenderLabel || '' if (!gender && d.Gender) { gender = /^FEMALE$/i.test(d.Gender) ? '女性' : /^MALE$/i.test(d.Gender) ? '男性' : d.Gender } if (/女性|FEMALE/i.test(gender)) { await chooseRadioButton(S('rblOwnerSex'), 'FEMALE') } else if (gender) { await chooseRadioButton(S('rblOwnerSex'), 'MALE') } } catch { /* gender */ } // メールアドレス try { if (d.Email) await fillInput(S('tbOwnerMailAddr'), d.Email) } catch { /* email */ } // 住所(V1: Street1/Street2 / V2: Street/Building) try { await delay(3500); if (d.Zip) { await fillInput(S('tbOwnerZip'), d.Zip) document.querySelector('#ctl00_ContentPlaceHolder1_ucInputForm_rCartList_ctl00_lbSearchOwnergAddr').click() try { await waitForValue(S('tbOwnerAddr2')) } catch { if (d.Prefecture) await chooseSelectBox(S('ddlOwnerAddr1'), d.Prefecture) await delay(5000); } } await delay(500); if (d.City) await fillInput(S('tbOwnerAddr2'), d.City) const street = d.Street1 || d.Street || ''; const building = d.Street2 || d.Building || ''; if (street) await fillInput(S('tbOwnerAddr3'), street) if (building) await fillInput(S('tbOwnerAddr4'), building) } catch { /* address */ } // メール配信(V1: mailFlg / V2: MailMagazine) try { const mailFlg = d.mailFlg || d.MailMagazine || '' if (mailFlg && !/配信する/.test(mailFlg)) { const mailCb = document.querySelector(S('cbOwnerMailFlg')) if (mailCb) mailCb.click() } } catch { /* mailFlg */ } // パスワード try { if (d.Password) { const pwdEl = document.querySelector(S('tbUserPassword')); const pwdConfEl = document.querySelector(S('tbUserPasswordConf')); if (pwdEl) { await fillInput(S('tbUserPassword'), d.Password); pwdEl.focus() } if (pwdConfEl) { await fillInput(S('tbUserPasswordConf'), d.Password); pwdConfEl.focus() } } } catch { /* password */ } // 電話番号(V1: PhoneNumber / V2: Tel) try { const tel = d.Tel || d.PhoneNumber || '' const telEl = document.querySelector(S('tbOwnerTel1')); if (tel && telEl) { await fillInput(S('tbOwnerTel1'), tel); telEl.focus() } } catch { /* tel */ } // 支払い方法(V1: payment / V2: PaymentLabel) const payment = d.payment || d.PaymentLabel || '' const creditCardSelectors = [ S('rPayment$ctl01$cbRegistCreditCard'), S('rPayment$ctl00$cbRegistCreditCard'), S('rPayment$ctl02$cbRegistCreditCard') ]; const creditCardNoSelectors = [ S('rPayment$ctl01$tbCreditCardNo1'), S('rPayment$ctl00$tbCreditCardNo1'), S('rPayment$ctl02$tbCreditCardNo1') ]; if (/NP後払い/.test(payment)) { await chooseSelectBox(S('ddlPayment'), "K36") await waitForElement(['#ctl00_ContentPlaceHolder1_ucInputForm_UpdatePanel1 a'], 100 * 1000) setTimeout(() => { const btn = document.querySelector('#ctl00_ContentPlaceHolder1_ucInputForm_UpdatePanel1 a') || document.querySelector('#ctl00_ContentPlaceHolder1_ucInputForm_UpdatePanel1 li a'); if (btn) btn.click(); }, 3000) setTimeout(hideLoadingScreen, 5000) } else if (/クレジットカード/.test(payment)) { await delay(1000); await chooseSelectBox(S('ddlPayment'), "K10") await waitForElement(creditCardSelectors, 100 * 1000) setTimeout(() => scrollToSelector(creditCardNoSelectors), 3000) sessionStorage.removeItem('bindingDone') hideLoadingScreen() } else { hideLoadingScreen() throw new Error("No Payment Selected!") } } catch (error) { console.log("Error => ", error) hideLoadingScreen() } } // --- 暗号化/復号 --- async function encryptData(data, password) { const enc = new TextEncoder(); const key = await crypto.subtle.importKey("raw", enc.encode(password), { name: "PBKDF2" }, false, ["deriveKey"]); const salt = crypto.getRandomValues(new Uint8Array(16)); const derivedKey = await crypto.subtle.deriveKey( { name: "PBKDF2", salt, iterations: 100000, hash: "SHA-256" }, key, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"] ); const iv = crypto.getRandomValues(new Uint8Array(12)); const encryptedData = await crypto.subtle.encrypt({ name: "AES-GCM", iv }, derivedKey, enc.encode(data)); return { salt: Array.from(salt), iv: Array.from(iv), data: Array.from(new Uint8Array(encryptedData)) }; } async function decryptData(encrypted, password) { const enc = new TextEncoder(); const key = await crypto.subtle.importKey("raw", enc.encode(password), { name: "PBKDF2" }, false, ["deriveKey"]); const salt = new Uint8Array(encrypted.salt); const iv = new Uint8Array(encrypted.iv); const derivedKey = await crypto.subtle.deriveKey( { name: "PBKDF2", salt, iterations: 100000, hash: "SHA-256" }, key, { name: "AES-GCM", length: 256 }, false, ["encrypt", "decrypt"] ); const decryptedData = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, derivedKey, new Uint8Array(encrypted.data)); return new TextDecoder().decode(decryptedData); } // --- ローディング画面 --- function showLoadingScreen() { const loadingScreen = document.createElement('div'); loadingScreen.id = 'dynamicLoadingScreen'; Object.assign(loadingScreen.style, { position: 'fixed', top: '0', left: '0', width: '100%', height: '100%', backgroundColor: 'rgba(255, 255, 255, 0.9)', display: 'flex', justifyContent: 'center', alignItems: 'center', flexDirection: 'column', color: '#333', zIndex: '9999999999', backdropFilter: 'blur(10px)', webkitBackdropFilter: 'blur(10px)' }); const spinner = document.createElement('div'); Object.assign(spinner.style, { border: '16px solid #f3f3f3', borderTop: '16px solid #3498db', borderRadius: '50%', width: '120px', height: '120px', animation: 'spin 2s linear infinite' }); loadingScreen.appendChild(spinner); const loadingText = document.createElement('p'); loadingText.textContent = '処理中です。そのままお待ちください。'; loadingScreen.appendChild(loadingText); const cautionText = document.createElement('p'); cautionText.textContent = '決済処理を安全に行うため、注文完了画面が表示されるまでブラウザを閉じたり、前の画面に戻ったりしないでください。'; Object.assign(cautionText.style, { textAlign: 'center', padding: '0 20px', lineHeight: '1.8' }); loadingScreen.appendChild(cautionText); const noteText = document.createElement('p'); noteText.textContent = '※入力内容にエラーがあった場合は、遷移先のページで修正をしてください。'; Object.assign(noteText.style, { textAlign: 'center', padding: '0 20px', fontSize: '0.9em', lineHeight: '1.8' }); loadingScreen.appendChild(noteText); document.body.appendChild(loadingScreen); const styleSheet = document.createElement('style'); styleSheet.innerHTML = '@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }'; document.head.appendChild(styleSheet); } function hideLoadingScreen() { const loadingScreen = document.getElementById('dynamicLoadingScreen'); if (loadingScreen) loadingScreen.style.display = 'none'; } }())