Skip to Content

Nesbitt Associates

Lead Capture

Photograph a business card, review the details filled in for you, and send it directly to Nesbitt.

1

Photograph the card

Use your phone camera to take a clear picture of the business card.

2

Add what is helpful

Review the card details filled in automatically and add any helpful notes.

3

Send to Nesbitt

Your personalized link routes the card to the correct sales rep.

Business card photo

Make sure the printed information is readable. The card will be read automatically after you take the photo.

Take or upload a photo *

For best results, place the card on a flat surface with good lighting.

Business card preview

Contact information

Google will suggest the card details below. Review and correct them before submitting. If the company or lead name cannot be read, enter it manually. Everything else is optional.

This becomes the lead title in CRM.

Lead details

Add anything the office or assigned rep should know about this conversation.

The photograph is read securely to suggest contact details, then sent with the reviewed information to Odoo. This tool does not automatically change ownership of an existing account.

Card sent successfully

The business card and any details you entered are now in Nesbitt Odoo and routed to the rep connected to this link.

(() => { const USC = '/shop/category/usc-6'; const KEY = 'nesbitt_usc_case_packs_v1'; const minimumFor = name => /POSTCARD|STICKER/i.test(name || '') ? 25 : 12; const normalize = (value, minimum) => { const quantity = Number(value) || 0; return quantity <= 0 ? 0 : Math.max(minimum, Math.ceil(quantity / minimum) * minimum); }; const readMap = () => { try { return JSON.parse(sessionStorage.getItem(KEY) || '{}'); } catch (_) { return {}; } }; const remember = (path, minimum) => { try { const values = readMap(); values[path] = minimum; sessionStorage.setItem(KEY, JSON.stringify(values)); } catch (_) {} }; const applyMinimum = (input, minimum) => { if (!input) return; input.dataset.uscCase = String(minimum); input.min = String(minimum); input.step = String(minimum); const corrected = normalize(input.value, minimum); if (corrected) input.value = String(corrected); }; const setupProduct = () => { const input = document.querySelector('input[name="add_qty"]'); if (!input || !document.querySelector('a[href*="' + USC + '"]')) return; const minimum = minimumFor(document.querySelector('h1')?.textContent); applyMinimum(input, minimum); remember(location.pathname, minimum); }; const setupCartInput = async input => { const row = input.closest('tr, .o_cart_product, .js_cart_line') || input.parentElement?.parentElement; const link = row?.querySelector('a[href^="/shop/"]'); if (!link) return; const path = new URL(link.href, location.origin).pathname; let minimum = readMap()[path]; if (!minimum) { try { const html = await fetch(path, { credentials: 'same-origin' }).then(response => response.text()); const page = new DOMParser().parseFromString(html, 'text/html'); if (!page.querySelector('a[href*="' + USC + '"]')) return; minimum = minimumFor(page.querySelector('h1')?.textContent); remember(path, minimum); } catch (_) { return; } } applyMinimum(input, minimum); }; const setup = () => { setupProduct(); document.querySelectorAll('input.js_quantity').forEach(setupCartInput); }; const correct = input => { if (!(input instanceof HTMLInputElement) || !input.matches('input[data-usc-case]')) return false; const corrected = normalize(input.value, Number(input.dataset.uscCase || 0)); if (!corrected || input.value === String(corrected)) return false; input.value = String(corrected); return true; }; document.addEventListener('click', event => { const button = event.target.closest('button[aria-label="Add one"], button[aria-label="Remove one"]'); if (!button) return; const group = button.closest('.css_quantity, .input-group') || button.parentElement; const input = group?.querySelector('input'); const minimum = Number(input?.dataset.uscCase || 0); if (!minimum) return; event.preventDefault(); event.stopImmediatePropagation(); const current = Number(input.value) || minimum; input.value = String(button.getAttribute('aria-label') === 'Add one' ? current + minimum : Math.max(minimum, current - minimum)); input.dispatchEvent(new Event('change', { bubbles: true })); }, true); document.addEventListener('change', event => correct(event.target), true); document.addEventListener('blur', event => { if (correct(event.target)) event.target.dispatchEvent(new Event('change', { bubbles: true })); }, true); if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', setup); else setup(); let timer; new MutationObserver(() => { clearTimeout(timer); timer = setTimeout(setup, 120); }).observe(document.documentElement, { childList: true, subtree: true }); })();