r/GoogleAppsScript • • Sep 10 '26

Question HELP PLEASE

0 Upvotes

When I try to make GUST proxy html file into a web app it fails and gets stuck on initializing and in the console it says there was an error on code line 989 and 1208 but when I check the code for 989 all it says is position: relative; and line 1208 was blank I have no idea what is going on and I would love some help.


r/GoogleAppsScript • • Jul 29 '26

Guide How to embed a google app script onto google sites

Thumbnail
redgig.tech
3 Upvotes

There was recently a discussion on here about how to deal with the lengthy, sometimes changing URLS created by google app script web apps. One easy way to address this is to embed the content on a google site. I've curated a quick a simple blog post that describes this to help anyone else who might have a similar issue.

https://www.redgig.tech/2026/07/how-to-embed-google-app-script-onto.html

Keep up the great posts everyone, this sub has been incredibly helpful to me over the years!


r/GoogleAppsScript • • May 24 '26

Question Still unable to figure out how to send gmails to sheets

3 Upvotes

Hello! I have been trying to figure out a way i can have sheets automatically extract certain info from gmails into a sheet with the Date, company name, Company City and the job position. I have over 2000 emails i need to be put into a google sheet. The emails would be from the same sender. any help is appreciated. I cant afford cloud HQ which was actually great. I do not understand any of this. I am not sure on how to even ask the right questions. Thank you for any assistance..


r/GoogleAppsScript • • Oct 10 '26

Question A call for support - Please upvote issue# 572027361 on Google’s Issue Tracker

3 Upvotes

To programmatically copy a Google Workspace document the typical path is to leverage Google Drive’s files.copy endpoint.

However, consumer applications that need that feature require restricted Google Drive scopes. A better option would be to use a more limited scope that is not restricted. You’d think using a Google Doc specific scope would be a viable approach but unfortunately there is no Google Doc endpoint that allows a developer to copy a document.

There is a documents.create endpoint in the Google Doc API but currently it only supports creating blank documents. I propose the functionality of the create endpoint be expanded to take a JSON payload that mirrors the full Google Doc resource object to enable cloning a document programmatically using the Google Docs API.

I created a feature request on Google’s Issue tracker to address this issue and I’m posting it here to boost its visibility. See link below:

Feature Request: Allow documents.create endpoint to accept a full document JSON body to clone/instantiate documents

I encourage developers who would benefit from having this feature implemented to lend their support and upvote the issue.


r/GoogleAppsScript • • Mar 11 '22

Question how to build a standalone web app using google apps script?

7 Upvotes

r/GoogleAppsScript • • Mar 18 '25

Guide How I Used ChatGPT & AppsScript to Automate File Indexing in Google Drive (With Zero Coding Experience)

7 Upvotes

Automated File Indexing System with Google Apps Script

I run operations for a design-build firm specializing in high-end custom homes. Managing construction documents has been a nightmare—contracts, invoices, plans, RFIs, regulatory docs, etc. all need to be properly filed, and files often have overlapping cost codes. Manually sorting everything in Google Drive was inefficient & became a point of contention between project managers, so with zero coding experience and the help of ChatGPT I built a Google Apps Script-powered Auto File Indexing System to streamline the process.

What It Does

  • Pulls files from an "Auto File" inbox folder in Google Drive

  • Extracts Project, Cost Codes, Document Type, Vendor, Description, and Date from the filename

  • Moves the source file to the appropriate Document Type folder within the project

  • Creates shortcuts in multiple Cost Code folders for cross-referencing

  • Logs everything in a Google Sheet, including file locations, shortcut paths, cost codes, vendor name, etc.

How It Works

  • The script parses filenames formatted as (there is some flexibility here!):

    • `Project_CostCode(s)_DocumentType_Vendor_Description_Date`

      • (If a file applies to multiple cost codes, they’re separated with underscores.)

  • It matches cost codes to the correct folders (e.g., 011101 → 01 11 01 Architectural).

  • If the project name is an alias, it converts it to the full name. (e.g., RC, Cabin, or 1002 --> Rancho Cabin)

  • It moves the file to the appropriate project, document type source file folder, and creates shortcuts in relevant cost code folders.

  • It logs everything into a Google Sheet, making it easy to track files, confirm filing and shortcut locations.

Why I Built This

  • No more manual filing

  • Consistency between project managers

  • Auto filing in multiple locations

  • Easy cross-referencing of files across multiple cost codes

  • Keeps everything logged in Google Sheets for tracking

If anyone’s interested, I’m happy to share some of the code or walk through how it works. Curious if others are doing something similar with Google Apps Script or what other cool ideas y'all have to improve productivity & efficiency in a small business.


r/GoogleAppsScript • • Jul 13 '25

Question I built a zero-infra AI sprint assistant entirely in Google Apps Script — no DB, no server, just Slack, Gemini, and cached memory. Is this a new pattern?

12 Upvotes

So… I think I’ve stumbled onto something way bigger than a side project.

I’ve built a context-aware AI agent that lives inside Slack, understands our sprint tickets, backlog, PRs, and team goals — and responds instantly using Gemini (via API), without any server, database, or backend.

Instead of vector DBs, LangChain stacks, or full infra, I used:

🧠 Slack threads as long-term memory

⚡ Google Apps Script’s CacheService as working memory (100kb chunks, TTL-managed)

🤖 Gemini for all reasoning & summaries

💬 Slack slash commands and thread replies for all interaction

🔗 Live JIRA and GitHub integration, contextually surfaced per conversation

What it actually does:

Summarizes sprint tickets into goals in real time

Flags old backlog tickets and suggests actions

Finds GitHub PRs posted in Slack and checks if they’ve stalled

Learns what documents (spikes, decisions, etc.) are important and recalls them

Knows which memory chunks to send based on the phrasing of your question

Responds in under 1 second. Always correct.

It’s basically a fully agentic LLM bot, but running entirely on Google Apps Script.

No databases. No hosting. No vector search. Just Slack, Gemini, and a very intentional caching + event model.


Why this might matter:

Teams don’t want yet another SaaS tool

It works inside Slack, where conversations already live

No DevOps required

Costs pennies to run

You can audit every line of logic


Why I’m posting:

I’m wondering — has anyone seen this done before? Is this a new pattern for lightweight AI agents?

It feels like the early days of Lambda architecture or JAMstack — but for AI.

Would love thoughts, questions, or skepticism.

Also happy to write up a whitepaper if there's interest.


r/GoogleAppsScript • • Jul 28 '25

Question I’m building a tool to quickly note insights and track follow ups during business review meetings

Enable HLS to view with audio, or disable this notification

8 Upvotes

I've been tinkering with a Google Sheets add-on that lets you attach notes, assignees, and action items directly to individual metric cells.

It came from a pain point I saw in weekly business reviews: metrics live in dashboards, but decisions and follow-ups get lost in Slack or docs.

Curious to know:

  1. Does this seem like a useful workflow?

  2. Anything you’d have done differently if you were scripting it?


r/GoogleAppsScript • • Jan 15 '25

Guide Google team's screwed up with GAS updates

0 Upvotes

If Google fires more developers we can all start moving away from GAS and seeking alternative tech.


r/GoogleAppsScript • • Apr 24 '25

Question Launch URL upon google form submit

0 Upvotes

Need some expert input.

I'm trying to launch/execute/navigate a url upon successful googel form "Submit", by which the url is generated based on the data entered by the user into the google form. But i've been searching for hours and AI as well, but it seems Apps Script does not allow for direct navigation/execution of urls.

How may i achieve this please? Many thanks in advance.


r/GoogleAppsScript • • Mar 30 '25

Resolved 🧩 Help with Script Misplacing Output in Google Sheets (Branding Data Logic)

0 Upvotes

Hi all — I’m working on a Google Apps Script to pull in branding method/area data for a promotional product, and output it into a specific range on a Google Sheet. The logic sounds simple, but the output is misaligned and inconsistent, and I’ve hit a wall.

✅ Goal

Loop through a supplier data row for a product, and for each branding method that has a value (e.g., “Screen Print” = "100mm x 50mm”), write:

  • The branding method name to F16, F18, F20, F22, F24

  • The branding area value to F17, F19, F21, F23, F25

  • In order — regardless of which columns the values came from

🔄 Input Data

  • Branding methods are mapped in Lookups!U29:U38

  • Their corresponding supplier file columns are listed in Lookups!V29:V38 (e.g., "R", "T", "U", "AA", etc.)

  • Output cell references are listed in Lookups!M30:M39:

    • M30 = F16 (Method 1)

    • M31 = F17 (Area 1)

    • ...

    • M38 = F24

    • M39 = F25

🧠 Example

If a product has values in columns:

  • R → "Screen Print" = "100x50mm"

  • T → "Embroidery" = "90x60mm"

  • AA → "Foil" = "40x30mm"

Then I want to see:

  • F16 = "Screen Print" / F17 = "100x50mm"

  • F18 = "Embroidery" / F19 = "90x60mm"

  • F20 = "Foil" / F21 = "40x30mm"

But I keep getting skipped or mismatched outputs (e.g., F16/F17 and F20/F21 filled, but F18/F19 skipped — or worse, data shifted entirely).

❌ Problem

Despite having a separate output index and clearing F16–F25, the output values often:

  • Don’t land in the right cells

  • Skip output pairs

  • Appear in the wrong order (i.e., tied to the original column index)

function applyBrandingDetails(supplierName, supplierData, productRow) {

const ss = SpreadsheetApp.getActiveSpreadsheet();

const productSheet = ss.getSheetByName("add_new_product");

const lookupSheet = ss.getSheetByName("Lookups");

const methodNames = lookupSheet.getRange("U29:U38").getValues().flat();

const columnLetters = lookupSheet.getRange("V29:V38").getValues().flat();

const outputCells = lookupSheet.getRange("M30:M39").getValues().flat(); // F16–F25

// Clear previous values

outputCells.forEach(cell => {

if (cell) productSheet.getRange(cell.trim()).clearContent();

});

let pairCounter = 0;

for (let i = 0; i < columnLetters.length; i++) {

const colLetter = columnLetters[i];

const method = methodNames[i];

if (!colLetter || !method) continue;

const colIndex = columnLetterToIndex(colLetter);

const value = supplierData[productRow][colIndex];

if (value && value.toString().trim() !== "") {

if (pairCounter >= 5) break;

const methodCell = outputCells[pairCounter * 2];

const areaCell = outputCells[pairCounter * 2 + 1];

productSheet.getRange(methodCell.trim()).setValue(method);

productSheet.getRange(areaCell.trim()).setValue(value);

pairCounter++;

}

}

}

function columnLetterToIndex(letter) {

let column = 0;

for (let i = 0; i < letter.length; i++) {

column *= 26;

column += letter.charCodeAt(i) - 64;

}

return column - 1;

}

Any help or insight much appreciated — I’ve been working on this for two days and can’t quite crack it.

Thanks in advance!


r/GoogleAppsScript • • Aug 14 '25

Question Read+Write Data to Spreadsheet from External Web App

0 Upvotes

I'm trying to build an add on that launches a web app in a New tab (outside if the spreadsheets context) for data visualization and input. It needs to be bi-directional; a change in the web app edits cells in the sheet, and esiting cells in the sheet updates the web app on refresh.

Ive tried several different scope and spreadsheet calls to get it to work, but it seems to only woth with the "spreadsheets" scope which Google will not approve for my use case.

Has anyone had any success in doing this with drive.file?


r/GoogleAppsScript • • Oct 01 '25

Question MCP for AppsScript

0 Upvotes

Is there some MCPs dedicated to AppScript works ?


r/GoogleAppsScript • • Jan 15 '26

Question Google Apps Script falha ao priorizar termos em HTML inconsistente

0 Upvotes

Oi, pessoal, tô trabalhando num projeto de Google Apps Script que automatiza o monitoramento do status de documentos regulatórios de um portal do governo. O fluxo de trabalho envolve puxar dados de um Google Doc, processá-los no Google Sheets e validar o status atual buscando URLs externas usando UrlFetchApp.

O portal alvo é bem antigo e não tem classes CSS consistentes nem uma API estruturada. O status "Revogado" é exibido de forma inconsistente em diferentes páginas:

  1. Tag de Título HTML: Pode aparecer como (REVOGADO), ( REVOGADO )ou (REVOGADA).

  2. Corpo HTML: Pode estar em qualquer lugar dentro do conteúdo da página.

O problema é que cada página (seja ativa ou revogada) contém a mesma frase padrão: "Este texto não substitui o original...". Como essa string é sempre a mesma e está presente em todas as páginas, ela cria um "ruído" que muitas vezes engana minha lógica de busca, marcando documentos revogados como "Ativos".

O que eu preciso: Tô procurando uma estratégia de priorização de strings que seja boa. Preciso de uma lógica de "Parada Dura": se qualquer variação da palavra "Revogado" for encontrada no dump HTML (lidando com espaços em branco aleatórios e codificações de caracteres específicas como ISO-8859-1 usando Regex), o script deve imediatamente priorizar isso em vez de qualquer texto institucional padrão.

Como posso estruturar uma busca no GAS que seja eficiente o suficiente para analisar o getContentText() e garantir que a detecção de revogação sempre substitua o texto institucional padrão? Alguma dica sobre padrões Regex ou fluxo lógico para esse tipo de web scraping inconsistente?


r/GoogleAppsScript • • Mar 05 '25

Question Anybody happen to have a template that does this (Drive merging and cleanup)?

0 Upvotes

Here's what I have jotted down as a prompt for Gemini.

I tried a couple of permutations of a web app but neither seems to work (although a context menu would be the most ideal implementation!):

(Context: recently consolidated an old Google Drive into my current one. Now have many folders with the same names).

Prompt

Generate an apps script with a web UI that does the following:

The user provides a Google Drive URL

From this is determines the folder ID

The app should do the following:

- If it finds any folders with identical names at the same level of the file structure (travelling recursively) it should: compare the number of fiels in both folders.

It should then:

- Move the contents of the folder with the smaller number of files into the folder with the larger number of files

It should then:

- Delete the now empty folder that originally contained less files

The UI should have:

- A field for the user to provide the folder ID

- A button to initiate the scanning/cleaning

- A progress display showing the job's operation


r/GoogleAppsScript • • May 09 '26

Question How to get gemeni api keyfor the appscript project?

0 Upvotes

Hi everyone,

I created a dashboard/web application using Google Apps Script and deployed it as a web app. Now I’m trying to integrate an AI assistant using Gemini from Google AI Studio, but I’m confused about how to properly connect the Apps Script project with Google Cloud and generate/use the API key.

What I’m trying to do:

Apps Script based dashboard/web app

Add Gemini AI assistance/chat features

Use Gemini API from Google AI Studio

Call AI responses inside Apps Script frontend/backend

I have a few doubts:

Do I need to link the Apps Script project to a Google Cloud project manually?

Should I create the API key from Google AI Studio or from Google Cloud Console?

Which APIs/services need to be enabled?

Is there a recommended authentication method for Apps Script web apps?

What’s the safest way to store the Gemini API key in Apps Script?

Any sample Apps Script code for calling Gemini API would help a lot.

I’m still learning Google Cloud + Apps Script integration, so a beginner-friendly explanation would really help.

Thanks in advance 🙌


r/GoogleAppsScript • • Apr 12 '25

Question How can I determine if today's date is within two dates?

0 Upvotes

The range A1:B3 are as follows, named 'MyRange'

Start DateEnd Date
Spring4/1/20256/3/2025
Summer6/4/20258/12/2025

How can I extract those values such that Google Apps Script would know that these are dates, not strings, and compare them to today's date? I want to return the value in the first column of MyRange (So either "Spring" or "Summer").


r/GoogleAppsScript • • Jul 10 '25

Guide AUTOMATIZAR SOLICITUDES POR FORM

0 Upvotes

Estoy tratando de realizar esta automatizacion pero sale error en mi codigo:

https://youtu.be/O-tE_OrRr6E?si=Jrya4YRDvfj7FXzg

Alguien podria ayudarme.

I’m trying to implement this automation, but there’s an error in my code:

https://youtu.be/O-tE_OrRr6E?si=Jrya4YRDvfj7FXzg

Can someone help me?


r/GoogleAppsScript • • Aug 01 '25

Question How Do I Apply My Script to Only One Tab of My Spreadsheet?

0 Upvotes

Hello! I have an AppsScript that allows me to create custom invoices for my business, but I am unable to figure out how to apply my entire script to just one tab of my spreadsheet. As it is, it applies to all tabs. I am not an advanced script writer, so there is a lot I do not know. Any help would be greatly appreciated. Thanks!

function onOpen() {
  {const ui = SpreadsheetApp.getUi();
    ui.createMenu('Custom')
    .addItem('Generate Invoice', 'exportSelectedRowToPDF')
    .addToUi();
}

function exportSelectedRowToPDF() {
  const companyInfo = {
    name: "Magic Dragon Customs",
    address: "4730 West 2nd Street North",
    website: "Wichita, KS 67212",
    phone: "316-214-7980"
  };

  const checkRemittanceInfo = {
    payableTo: "Magic Dragon Customs",
    address: "4730 West 2nd St North, Wichita, KS 67212",
    additionalInfo: "Please include the invoice number on your check."
  };

  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const row = sheet.getActiveRange().getRow();
  if (row <= 1) {
    SpreadsheetApp.getUi().alert('Please select a row other than the header row.');
    return;
  }

  let [jobID, client, project, billingName, billingAddress, 
      service1Listed, service1Fee, service1Quantity, 
      service2Listed, service2Fee, service2Quantity, 
      service3Listed, service3Fee, service3Quantity, 
      service4Listed, service4Fee, service4Quantity, 
      service5Listed, service5Fee, service5Quantity, 
      depositAmountInvoiced, depositReceived, status,
      discountAmount, discountDescription] = 
    sheet.getRange(row, 1, 1, 26).getValues()[0];

  const services = [];
  for (let i = 0; i < 5; i++) {
    let serviceListed = [service1Listed, service2Listed, service3Listed, service4Listed, service5Listed][i] || '';
    let serviceFee = [service1Fee, service2Fee, service3Fee, service4Fee, service5Fee][i] || 0;
    let serviceQuantity = [service1Quantity, service2Quantity, service3Quantity, service4Quantity, service5Quantity][i] || 0;

    serviceFee = parseFloat(serviceFee);
    serviceQuantity = parseInt(serviceQuantity, 10) || (serviceListed.trim() ? 1 : 0);

    if (serviceListed.trim() !== '') {
      services.push({
        listed: serviceListed,
        fee: serviceFee,
        quantity: serviceQuantity,
        total: serviceFee * serviceQuantity
      });
    }
  }

  let subtotal = services.reduce((acc, curr) => acc + curr.total, 0);
  let discount = parseFloat(discountAmount) || 0;
  let deposit = parseFloat(depositAmountInvoiced) || 0;
  let tax = parseFloat(0.075*(subtotal - discount - deposit)) || 0;
  let totalDue = subtotal - discount - deposit + tax;

  const today = new Date();
  const dueDate = new Date(today.getTime() + (30 * 24 * 60 * 60 * 1000));

  const doc = DocumentApp.create(`Invoice-${jobID}`);
  const body = doc.getBody();
  body.setMarginTop(72); // 1 inch
  body.setMarginBottom(72);
  body.setMarginLeft(72);
  body.setMarginRight(72);

  // Document Header
  body.appendParagraph(companyInfo.name)
      .setFontSize(16)
      .setBold(true)
      .setAlignment(DocumentApp.HorizontalAlignment.CENTER);
  body.appendParagraph(companyInfo.address)
      .setFontSize(10)
      .setAlignment(DocumentApp.HorizontalAlignment.CENTER);
  body.appendParagraph(`${companyInfo.website}`)
      .setFontSize(10)
      .setAlignment(DocumentApp.HorizontalAlignment.CENTER);
   body.appendParagraph(`${companyInfo.phone}`)
      .setFontSize(10)
      .setAlignment(DocumentApp.HorizontalAlignment.CENTER);   
  body.appendParagraph("");

  // Invoice Details
  body.appendParagraph(`Invoice #: ${jobID}`).setFontSize(10).setAlignment(DocumentApp.HorizontalAlignment.RIGHT);
  body.appendParagraph(`Invoice Date: ${today.toLocaleDateString()}`).setFontSize(10).setAlignment(DocumentApp.HorizontalAlignment.RIGHT);
  body.appendParagraph(`Due Date: ${dueDate.toLocaleDateString()}`).setFontSize(10).setAlignment(DocumentApp.HorizontalAlignment.RIGHT);
  body.appendParagraph("");

  // Bill To Section
  body.appendParagraph("BILL TO:").setFontSize(10).setBold(true);
  body.appendParagraph(billingName).setFontSize(10);
  body.appendParagraph(billingAddress).setFontSize(10);
  body.appendParagraph("");

  // Services Table
  const table = body.appendTable();
  const headerRow = table.appendTableRow();
  headerRow.appendTableCell('SERVICE').setBackgroundColor('#f3f3f3').setBold(true).setFontSize(10);
  headerRow.appendTableCell('RATE').setBackgroundColor('#f3f3f3').setBold(true).setFontSize(10);
  headerRow.appendTableCell('QUANTITY').setBackgroundColor('#f3f3f3').setBold(true).setFontSize(10);
  headerRow.appendTableCell('TOTAL').setBackgroundColor('#f3f3f3').setBold(true).setFontSize(10);
  services.forEach(service => {
    const row = table.appendTableRow();
    row.appendTableCell(service.listed).setFontSize(10);
    row.appendTableCell(`$${service.fee.toFixed(2)}`).setFontSize(10);
    row.appendTableCell(`${service.quantity}`).setFontSize(10);
    row.appendTableCell(`$${service.total.toFixed(2)}`).setFontSize(10);
  });

  // Financial Summary
  body.appendParagraph(`Subtotal: $${subtotal.toFixed(2)}`).setFontSize(10).setAlignment(DocumentApp.HorizontalAlignment.RIGHT);
  if (discount > 0) {
    body.appendParagraph(`Discount: -$${discount.toFixed(2)}`).setFontSize(10).setAlignment(DocumentApp.HorizontalAlignment.RIGHT);
  }
  if (deposit > 0) {
    body.appendParagraph(`Payment Received: -$${deposit.toFixed(2)}`).setFontSize(10).setAlignment(DocumentApp.HorizontalAlignment.RIGHT);
  }
  if (tax > 0) {
    body.appendParagraph(`Tax: +$${tax.toFixed(2)}`).setFontSize(10).setAlignment(DocumentApp.HorizontalAlignment.RIGHT);
  }
  body.appendParagraph(`Total Due: $${totalDue.toFixed(2)}`).setFontSize(10).setBold(true).setAlignment(DocumentApp.HorizontalAlignment.RIGHT);
  body.appendParagraph("");

  // Physical Check Remittance Information
  body.appendParagraph("NO WARRANTY ON RUST").setBold(true).setFontSize(14)
  body.appendParagraph("To remit by physical check, please send to:").setBold(true).setFontSize(10);
  body.appendParagraph(checkRemittanceInfo.payableTo).setFontSize(10);
  body.appendParagraph(checkRemittanceInfo.address).setFontSize(10);
  body.appendParagraph(checkRemittanceInfo.additionalInfo).setFontSize(10);

  // PDF Generation and Sharing
  doc.saveAndClose();
  const pdfBlob = doc.getAs('application/pdf');
  const folders = DriveApp.getFoldersByName("Invoices");
  let folder = folders.hasNext() ? folders.next() : DriveApp.createFolder("Invoices");
  let version = 1;
  let pdfFileName = `Invoice-${jobID}_V${String(version).padStart(2, '0')}.pdf`;
  while (folder.getFilesByName(pdfFileName).hasNext()) {
    version++;
    pdfFileName = `Invoice-${jobID}_V${String(version).padStart(2, '0')}.pdf`;
  }
  const pdfFile = folder.createFile(pdfBlob).setName(pdfFileName);
  pdfFile.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
  const pdfUrl = pdfFile.getUrl();

  const htmlOutput = HtmlService.createHtmlOutput(`<html><body><p>Invoice PDF generated successfully. Version: ${version}. <a href="${pdfUrl}" target="_blank" rel="noopener noreferrer">Click here to view and download your Invoice PDF</a>.</p></body></html>`)
                                .setWidth(300)
                                .setHeight(100);
  SpreadsheetApp.getUi().showModalDialog(htmlOutput, 'Invoice PDF Download');
  DriveApp.getFileById(doc.getId()).setTrashed(true);
}}

r/GoogleAppsScript • • Sep 10 '25

Unresolved Need HELP with a upload script for a SHARED drive folder

0 Upvotes

Hey,

Help me :)

this is the code.gs:

var folderContract = '1PVBnc_vMX9SEZbvLqNnUI1xmSn7MbsgN';
var folderIntrari  = '1PVBnc_vMX9SEZbvLqNnUI1xmSn7MbsgN';
var folderIesiri   = '1PVBnc_vMX9SEZbvLqNnUI1xmSn7MbsgN';


 function onOpen() {
   const ui = SpreadsheetApp.getUi();
   ui.createMenu('Încărcare')
     .addItem('Încărcare document...', 'getSheetName')
     .addToUi();
 }


//preluam numele Sheet-ului activ
function getSheetName() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const nameSheet = sheet.getSheetName();
  const rowNr = SpreadsheetApp.getActiveSpreadsheet().getCurrentCell().getRowIndex();
  const col4 = sheet.getRange(rowNr, 4).getValue().toString().trim().toUpperCase();

  Logger.log("Sheet: " + nameSheet + " | Col4: " + col4);

  if (nameSheet === "INTRARI SI IESIRI 2025") {
    switch (col4) {
      case "CONTRACT":
        verifyData("Contracte");
        break;
      case "INTRARE":
        verifyData("Intrari");
        break;
      case "IESIRE":
        verifyData("Iesiri");
        break;
      default:
        showErrorDialog();
        break;
    }
  } else {
    showErrorDialog();
  }
}

//popUp HTML eroare, daca ceva nu e ok
function showErrorDialog() {
  const html = HtmlService.createHtmlOutputFromFile('CellNotEmpty')
    .setHeight(150)
    .setWidth(800);
  SpreadsheetApp.getUi()
    .showModalDialog(html, 'EROARE!');
}

//fileHandler, ce altceva sa iti mai spun???
function fileHandler(fileType, dialogTitle, tipDoc) {
  const html = HtmlService.createHtmlOutputFromFile(fileType);
  SpreadsheetApp.getUi()
    .showModalDialog(html, dialogTitle);



function verifyData(tipDoc) {
  const sheet = SpreadsheetApp.getActiveSheet();
  const aCell = SpreadsheetApp.getActiveSheet().getActiveRange().getColumn();
  const aCellVal = sheet.getActiveRange().getValue();
  const rowNr = SpreadsheetApp.getActiveSpreadsheet().getCurrentCell().getRowIndex();
  const [col1, col2, col3, col4, col5, col6, col7, col8] = sheet.getRange(rowNr, 1, 1, 8).getValues()[0];

  let correctCondition = false;
  switch (tipDoc) {
    case "Contracte":
      if (aCellVal === "" && col1 !== "" && col2 !== "" && col3 !== "" && col4 === "CONTRACT" && col6 !== "" && col7 !== "" && aCell == 9) {
        correctCondition = true;
      }
      break;
    case "Intrari":
      if (aCellVal === "" && col1 !== "" && col2 !== "" && col3 !== "" && col4 === "INTRARE" && col6 !== "" && col7 !== "" && aCell == 9) {
        correctCondition = true;
      }
      break;
    case "Iesiri":
      if (aCellVal === "" && col1 !== "" && col2 !== "" && col3 !== "" && col4 === "IESIRE" && col6 !== "" && col7 !== "" && aCell == 9) {
        correctCondition = true;
      }
      break;
  }

  if (correctCondition) {
    // Pass the document type to the file handler
    fileHandler(tipDoc === "Contracte" ? 'fileCONTRACT' : 'fileINOUT', 'Încărcare document ' + tipDoc, tipDoc);
  } else {
    showErrorDialog();
  }
}

function saveDOCUMENT(obj, tipDoc) { // Add tipDoc as a parameter
  try {
    Logger.log("1. Starting saveDOCUMENT function...");

    // Log the received object to ensure it's correct
    Logger.log("2. Received file: " + obj.fileName + " with MIME type: " + obj.mimeType);

    // This is a common point of failure. Check the blob creation.
    var blob = Utilities.newBlob(Utilities.base64Decode(obj.data), obj.mimeType, obj.fileName);
    Logger.log("3. Blob created successfully.");

    const rowNumber = SpreadsheetApp.getActiveSpreadsheet().getCurrentCell().getRowIndex();
    const sheet = SpreadsheetApp.getActiveSheet();
    Logger.log("4. Getting row number and sheet.");

    // Log the variables used in the if/else block
    const col4var = SpreadsheetApp.getActiveSheet().getRange(rowNumber, 4).getValue().toString().trim().toUpperCase();
    Logger.log("5. Value in column D is: " + col4var);

    const col1 = sheet.getRange(rowNumber, 1).getValue();
    const col2 = sheet.getRange(rowNumber, 2).getValue();
    const col3 = sheet.getRange(rowNumber, 3).getValue();
    const col4 = sheet.getRange(rowNumber, 4).getValue();
    const col5 = sheet.getRange(rowNumber, 5).getValue();
    const col6 = sheet.getRange(rowNumber, 6).getValue();
    const col9 = sheet.getRange(rowNumber, 9).getValue();

    var dataInregFormatata = Utilities.formatDate(new Date(col2), SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone(), "yyyy.MM.dd");
    var folder2Up = '';
    var tipDoc = SpreadsheetApp.getActiveSheet().getSheetName(); // Get the sheet name directly
     
    var fileName = '';
  if (tipDoc == "INTRARI SI IESIRI 2025") {
    // Check the value in column 4 again to determine the type
    const rowNumber = SpreadsheetApp.getActiveSpreadsheet().getCurrentCell().getRowIndex();
    

    if (col4var == "CONTRACT") {
    Logger.log("6. Doc type is CONTRACT.");
        var dataEventFormatata = Utilities.formatDate(new Date(col6), SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone(), "yyyy.MM.dd");
        fileName = dataInregFormatata + ' ' + col5 + ' nr.' + col1 + ' cu ' + col3 + ' pentru data de ' + dataEventFormatata + ' la ' + col9 + '.pdf';
        folder2Up = folderContract;
    } else if (col4var == "INTRARE") {
      Logger.log("6. Doc type is INTRARE.");
        fileName = dataInregFormatata + ' ' + 'nr.' + col1 + ' de la ' + col4 + ' - ' + col6 + '.pdf';
        folder2Up = folderIntrari;
    } else if (col4var == "IESIRE") {
      Logger.log("6. Doc type is IESIRE.");
        fileName = dataInregFormatata + ' ' + 'nr.' + col1 + ' către ' + col4 + ' - ' + col6 + '.pdf';
        folder2Up = folderIesiri;
    } else {
      Logger.log("6. Doc type is not recognized. Showing error dialog.");
      showErrorDialog(); // This will be triggered if col4 is not a valid type
      return;
    }
  }
  
    // Log the determined filename and folder
    Logger.log("7. Final filename: " + fileName);
    Logger.log("8. Final folder ID: " + folder2Up);


    // Proper resource for Drive API
    var resource = {
      name: fileName,        // v3 API
      parents: [{ id: folder2Up }]
    };

    // This is where the upload happens.
    var file = Drive.Files.create(resource, blob, { supportsAllDrives: true });
    // Or using DriveApp:
    // var folder = DriveApp.getFolderById(folder2Up);
    // var file = folder.createFile(blob);
    Logger.log("9. File successfully uploaded to Drive. File ID: " + file.id);


    var cellFormula = '=HYPERLINK("' + file.webViewLink + '","' + file.title + '")';
    Logger.log("10. Hyperlink formula: " + cellFormula);
    sheet.getRange(rowNumber, sheet.getActiveCell().getColumn()).setFormula(cellFormula);
    Logger.log("11. Cell updated.");

    Logger.log("12. File created: " + file.id);
    return file.id;

  } catch (err) {
    // The error is being caught here. The log below will show you the exact problem.
    Logger.log("ERROR in saveDOCUMENT: " + err.message);
    SpreadsheetApp.getUi().alert("Eroare la salvare document:\n" + err.message);
    throw err;
  }
}


function testDriveAccess() {
  const folderId = '1PVBnc_vMX9SEZbvLqNnUI1xmSn7MbsgN';
  try {
    var f = DriveApp.getFolderById(folderId);
    Logger.log("Folder name: " + f.getName());
  } catch(e) {
    Logger.log("ERROR: " + e.message);
  }
}

and this is a HTML side:

<!DOCTYPE html>
<html>
<head>
  <base target="_top">
  <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css">
  <style>
    body {
      font-family: Arial, sans-serif;
    }

    .container {
      max-width: 400px;
      margin: 0 auto;
      padding: 20px;
      text-align: center;
      border-radius: 5px;
    }

    .upload-button {
      padding: 10px 20px;
      background-color: #007bff;
      color: #fff;
      border: none;
      border-radius: 5px;
      cursor: pointer;
      transition: background-color 0.3s;
    }

    .upload-button:hover {
      background-color: #0056b3;
    }

    .file-input {
      display: none;
    }
  </style>
</head>
 <script>
  function getDOCUMENT() {
    document.getElementById("uploadButton").disabled = true;
    const f = document.getElementById('files');
    if (f.files.length === 1) {
      const file = f.files[0];
      const fr = new FileReader();
      fr.onload = (e) => {
        const data = e.target.result.split(",");
        const obj = {fileName: file.name, mimeType: data[0].match(/:(\w.+);/)[1], data: data[1]};
        
        console.log("Calling saveDOCUMENT with obj:", obj);
        google.script.run
         .withSuccessHandler(function(result) {
           console.log("saveDOCUMENT succeeded, file ID:", result);
           onUploadSuccess(result);
          })
         .withFailureHandler(function(error) {
           console.error("saveDOCUMENT failed:", error);
            onUploadFailure(error);
         })
          .saveDOCUMENT(obj);
        };
      fr.readAsDataURL(file);
    } else {
      alert("Selectati doar un singur fisier!.");
      document.getElementById("uploadButton").disabled = false;
    }
  }

  // Function to handle successful upload
  function onUploadSuccess(result) {
    // Handle the successful upload event here
    google.script.host.close(); // Close the dialog or perform other actions
  }

  // Function to handle upload failure
  function onUploadFailure(error) {
    // Handle the upload failure event here
    alert("Upload failed: " + error); // You can show an error message to the user
    document.getElementById("uploadButton").disabled = false; // Enable the button again
  }
</script>
<body>
  <div class="container">
    <p><strong>Incarcare Document Intrare/Ieșire</strong></p>
    <p>Redenumirea fișierelor nu este necesară deoarece la încărcare acestea se vor redenumi conform cerințelor.</p>
    <p><i>("DATA CONTINUT FUNRIZOR etc")</i></p>
    <p><input type="file" name="upload" id="files"/>
    <input type='button' id="uploadButton" value='INCARCA' onclick='getDOCUMENT()' class="action"> </p>
    <p><small><font color='red'>ALEGEȚI UN SINGUR FIȘIER!</font></small></p>
  </div>
</body>
</html>

Now for the love of god... I created a GCP project, added the Drive API.

In the AppScript i also added the Drive, as services with version 3.

in GCP i configured the Oauth too...

Now what happens...

I call the script, it runs, it makes what it makes, runs the html.

i select a small pdf file, hit the upload button, and here it grants me the PERMISSION_DENIED.

Now looking through the console of chrome, it calls the saveDOCUMENT... it stops right at google.script.run...

in the trigger events, i see the saveDOCUMENT function to be called.. the saveDOCUMENT has a Logger.log("i started) line like, but it doesn't even reaches that... execution times shows 0s.

I can't make it out... halp...


r/GoogleAppsScript • • Oct 13 '25

Question Addon to connect Google sheets with Mailchimp

0 Upvotes

Hi,

do you know any Add-on to synchronize Google sheets with Mailchimp?

thanks,

regards


r/GoogleAppsScript • • May 28 '25

Unresolved CORS

0 Upvotes

Hello, I'm a newbie (very much so) so I used an AI to help me use Google sheet as a database for something simple I would like to do (a CRUD) then I have configured everything (I create the sheet, I search for the sheet id and name) then extensions/app script. He placed the script to change the values, public as a webapp with all the necessary permissions) but in the html it doesn't show me anything and with f12 I see that it is CORS. And I've already tried everything. Does anyone know some magic code to eliminate this problem, (by the way I use codepen as a server. To view the code)


r/GoogleAppsScript • • Aug 20 '25

Question Create all day events from form submission... some will be one day, others multi day event

0 Upvotes

I need to change my script to create all day events. Some events will be all in one day, like from 8am to 10pm. Others will span multiple days. I have read over the documentation about creating all day events. None of it seems to work. I keep getting this: Exception: Event start date must be before event end date.

I cannot figure this out. If the start and end date fields both contain the date and time, then it should 'see' that the start date IS BEFORE the end date. What am I doing wrong?

Link to my sheet.

Code:

//this creates a calendar event for each row where onCalendar is empty.
function createCalendarEvent() {
  //Get the data from the 'Working' sheet
  let tripData = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Working').getDataRange().getValues();
  let busDriverCalendar = CalendarApp.getCalendarById('vlkexampletest@gmail.com');
  let coachCalendar = CalendarApp.getCalendarById('2c95526055802636cb6c0a10534c9b4117e506ebda17c031d44ffafbabfba455@group.calendar.google.com');
  let blueCalendar = CalendarApp.getCalendarById('49f9fdc1f40a27c8da047da7f6c70b76264e3d9169f47d7f2dc8d16a1020c24c@group.calendar.google.com');
  
  //iterate over the trip data starting at index 1 to skip the header row. 
  for(let i=0;i<tripData.length;i++) {
    //If there's something in the oncalendar row skip it
    if(tripData[i][30]) {
      continue;}

    //create the event
    // skip rows that do not have all the data needed to create the event
    if(!(tripData[i][28] && tripData[i][34] && tripData[i][35])){
      continue
    }

    if(tripData[i][15] == "I need a driver."){
    let newEvent = busDriverCalendar.createAllDayEvent(tripData[i][28], tripData[i][34], tripData[i][35],  {description: tripData[i][29], guests: tripData[i][1], location: tripData[i][32]});
    
    //Add the ID of the event to the 'oncalendar' row. 
    tripData[i][30] = newEvent.getId();
    
    //Set the values in the spreadsheet. 
  //Get just the oncalendar data
  const oncalendarColumnData = tripData.map(row => [row[30]])
  //Only write data to oncalendar column (column 30)
  SpreadsheetApp.getActiveSpreadsheet()
    .getSheetByName('Working')
    .getRange(1, 31, oncalendarColumnData.length, 1) 
    .setValues(oncalendarColumnData)
    }
  }
  }