Created
June 4, 2024 23:27
-
-
Save Markkop/6d87a189622e7288eeb098d4b3527c63 to your computer and use it in GitHub Desktop.
gmail-to-zoho-invoice-generator.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Invoice Generator for Gmail | |
// @namespace http://tampermonkey.net/ | |
// @version 0.2 | |
// @description Generate invoices automatically from Gmail content and send to Zoho | |
// @author Mark Kop | |
// @match https://mail.google.com/* | |
// @match https://oauth.pstmn.io/v1/callback | |
// @grant GM_xmlhttpRequest | |
// @grant GM_setValue | |
// @grant GM_getValue | |
// @connect api.openai.com | |
// @connect www.googleapis.com | |
// @connect accounts.zoho.com | |
// @run-at document-idle | |
// ==/UserScript== | |
(function() { | |
'use strict'; | |
const openAiApiKey = ''; | |
const clientId = ''; | |
const clientSecret = ''; | |
const redirectUri = 'https://oauth.pstmn.io/v1/callback'; | |
const authUrl = `https://accounts.zoho.com/oauth/v2/auth?response_type=code&client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&scope=ZohoInvoice.fullaccess.all`; | |
const IDS = { | |
ORGANIZATION_ID: '', | |
CUSTOMER_ID: '', | |
ITEM_ID: '' | |
}; | |
function extractEmailContent() { | |
console.log('Extracting email content...'); | |
const emailBody = document.querySelector('.a3s'); | |
const emailContent = emailBody ? emailBody.innerText : null; | |
console.log('Email content:', emailContent); | |
return emailContent; | |
} | |
function generateInvoiceContent(emailContent) { | |
console.log('Generating invoice content...'); | |
return new Promise((resolve, reject) => { | |
GM_xmlhttpRequest({ | |
method: "POST", | |
url: "https://api.openai.com/v1/chat/completions", | |
headers: { | |
"Content-Type": "application/json", | |
"Authorization": `Bearer ${openAiApiKey}` | |
}, | |
data: JSON.stringify({ | |
model: "gpt-4-1106-preview", | |
messages: [{ | |
role: "system", | |
content: `Generate JSON with the following keys: customer_id (use ${IDS.CUSTOMER_ID} for this field), date (use format ${new Date().toISOString().split('T')[0]}), line_items (array of objects with keys: item_id (use ${IDS.ITEM_ID}), quantity (use 1), rate (use the value in dollars, number only)).` | |
}, { | |
role: "user", | |
content: emailContent | |
}], | |
max_tokens: 512, | |
response_format: { type: "json_object" } | |
}), | |
onload: function(response) { | |
console.log('OpenAI API response:', response); | |
const data = JSON.parse(response.responseText); | |
resolve(data.choices[0].message.content); | |
}, | |
onerror: function(err) { | |
console.error('Error during OpenAI API request:', err); | |
reject(err); | |
} | |
}); | |
}); | |
} | |
function createZohoInvoice(invoiceData) { | |
console.log('Creating Zoho invoice...'); | |
const token = GM_getValue('GM_zoho_token'); | |
if (!token) { | |
console.error('Zoho token is missing. Please authorize first.'); | |
initiateOAuthFlow(); | |
return; | |
} | |
console.log('Zoho token:', token); | |
console.log('Invoice data to be sent to Zoho:', invoiceData); | |
return new Promise((resolve, reject) => { | |
GM_xmlhttpRequest({ | |
method: "POST", | |
url: "https://invoice.zoho.com/api/v3/invoices", | |
headers: { | |
"Authorization": `Zoho-oauthtoken ${token}`, | |
"Content-Type": "application/json", | |
"X-com-zoho-invoice-organizationid": IDS.ORGANIZATION_ID || '' | |
}, | |
data: JSON.stringify(JSON.parse(invoiceData)), | |
onload: function(response) { | |
console.log('Zoho API response:', response); | |
const responseData = JSON.parse(response.responseText); | |
if (response.status === 401) { | |
console.error('Not authorized. Please check your Zoho token.'); | |
reject('Not authorized'); | |
} else { | |
resolve(responseData); | |
} | |
}, | |
onerror: function(err) { | |
console.error('Error during Zoho API request:', err); | |
reject(err); | |
} | |
}); | |
}); | |
} | |
function initiateOAuthFlow() { | |
console.log('Initiating OAuth flow...'); | |
window.open(authUrl, 'authPopup', 'width=500,height=500'); | |
} | |
function exchangeCodeForToken(code) { | |
console.log('Exchanging code for token...'); | |
GM_xmlhttpRequest({ | |
method: "POST", | |
url: "https://accounts.zoho.com/oauth/v2/token", | |
headers: { | |
"Content-Type": "application/x-www-form-urlencoded" | |
}, | |
data: `code=${code}&redirect_uri=${encodeURIComponent(redirectUri)}&client_id=${clientId}&client_secret=${clientSecret}&grant_type=authorization_code`, | |
onload: function(response) { | |
console.log('Token exchange response:', response); | |
const responseData = JSON.parse(response.responseText); | |
GM_setValue('GM_zoho_token', responseData.access_token); | |
processInvoice(); | |
}, | |
onerror: function(err) { | |
console.error('Failed to exchange code for token:', err); | |
} | |
}); | |
} | |
async function processInvoice() { | |
console.log('Processing invoice...'); | |
const token = GM_getValue('GM_zoho_token'); | |
if (!token) { | |
console.error('Zoho token is missing. Please authorize first.'); | |
initiateOAuthFlow(); | |
return; | |
} | |
const emailContent = extractEmailContent(); | |
if (!emailContent) { | |
alert('No email content found.'); | |
return; | |
} | |
try { | |
const invoiceDetails = await generateInvoiceContent(emailContent); | |
console.log('Generated invoice details:', invoiceDetails); | |
const zohoInvoiceData = await createZohoInvoice(invoiceDetails); | |
console.log('Zoho invoice data:', zohoInvoiceData); | |
} catch (error) { | |
console.error('Error:', error); | |
alert('An error occurred. Check the console for details.'); | |
} | |
} | |
function addButton() { | |
console.log('Adding button to the page...'); | |
const button = document.createElement('button'); | |
button.innerText = 'Generate Invoice'; | |
button.style.position = 'fixed'; | |
button.style.bottom = '10px'; | |
button.style.right = '10px'; | |
button.style.zIndex = 1000; | |
button.onclick = () => { | |
const url = new URL(window.location.href); | |
const code = url.searchParams.get('code'); | |
if (code) { | |
console.log('Authorization code found:', code); | |
exchangeCodeForToken(code); | |
} else { | |
processInvoice(); | |
} | |
}; | |
document.body.appendChild(button); | |
console.log('Button added.'); | |
} | |
if (window.location.href.startsWith('https://oauth.pstmn.io/v1/callback')) { | |
addButton(); | |
} else { | |
window.addEventListener('load', addButton); | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment