Add calendar event with the help of checkbox - google-apps-script

With reference to this question - Not able to create event on Calendar with this script
The Code after all changes:
function onOpen() {
SpreadsheetApp.getUi().createMenu('⇩ M E N U ⇩')
.addItem('👉 Set up ...', 'myTriggerSetup')
.addToUi();
}
function myTriggerSetup() {
var ssID = SpreadsheetApp.getActiveSpreadsheet().getId()
if (!isTrigger('onSpeEdit')) {
ScriptApp.newTrigger('onSpeEdit').forSpreadsheet(ssID).onEdit().create();
}
}
function isTrigger(funcName) {
var r = false;
if (funcName) {
var allTriggers = ScriptApp.getProjectTriggers();
var allHandlers = [];
for (var i = 0; i < allTriggers.length; i++) {
allHandlers.push(allTriggers[i].getHandlerFunction());
}
if (allHandlers.indexOf(funcName) > -1) {
r = true;
}
}
return r;
}
function onSpeEdit(e) {
var rg = e.range;
if (rg.getRow() == 57 && rg.isChecked() && rg.getSheet().getName() === "Course") {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Course');
var start = new Date(spreadsheet.getRange('U70').getValue()).getTime();
var end = new Date(spreadsheet.getRange('X69').getValue()).getTime();
var name = spreadsheet.getRange('U69').getValue()
var calend = CalendarApp.getDefaultCalendar();
calend.createEvent(name, new Date(start), new Date(end));
rg.uncheck();
}
}
My Requirement:
A user will fill all 3 cells for event details. Then, they will tick on checkbox and the event should get added and also checkbox should get untick. Then, another user will do the same process again.
My Issues:
It is working in the dummy sheet but not in main sheet.My above code is as per main sheet.
Dummy Sheet: https://docs.google.com/spreadsheets/d/1_f_dujqIvmkXXLAqyandEmrWOxgskIfk9KTSKw28UuA/edit#gid=0
Thank you:
Thank you, Mike and Tanaike for the amazing efforts to help me.

Try this
function onOpen() {
SpreadsheetApp.getUi().createMenu('⇩ M E N U ⇩')
.addItem('👉 Set up ...', 'myTriggerSetup')
.addToUi();
}
function myTriggerSetup() {
var ssID = SpreadsheetApp.getActiveSpreadsheet().getId()
if (!isTrigger('onSpeEdit')) {
ScriptApp.newTrigger('onSpeEdit').forSpreadsheet(ssID).onEdit().create();
}
}
function isTrigger(funcName) {
var r = false;
if (funcName) {
var allTriggers = ScriptApp.getProjectTriggers();
var allHandlers = [];
for (var i = 0; i < allTriggers.length; i++) {
allHandlers.push(allTriggers[i].getHandlerFunction());
}
if (allHandlers.indexOf(funcName) > -1) {
r = true;
}
}
return r;
}
function onSpeEdit(e) {
var rg = e.range;
if (rg.getRow() == 4 && rg.isChecked() && rg.getSheet().getName() === "Course") {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Course');
var start = new Date(rg.offset(-2,0).getValue()).getTime();
var end = new Date(rg.offset(-1,0).getValue()).getTime();
var name = rg.offset(-3,0).getValue();
var calend = CalendarApp.getDefaultCalendar();
calend.createEvent(name, new Date(start), new Date(end));
rg.uncheck();
}
}

1. Rename your function name as follows.
In this case, you can also use the other function names except for onEdit. About the reason of this, you can see it at this thread.
function installedOnEdit(e){
var rg = e.range;
if(rg.getA1Notation() === "Z56" && rg.isChecked() && rg.getSheet().getName() === "Course"){
calendar(); //calling calendar function
rg.uncheck()
SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Course').getRange('X57').setValue('Event has been added to your Calendar')//Putting message in cell x57;
}
}
2. Install the installable OnEdit trigger to the renamed function.
You can see how to manually install this at the official document.
If you are required to use a script, you can also the following script.
function installTrigger() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
ScriptApp.newTrigger("installedOnEdit").forSpreadsheet(ss).onEdit().create();
}
By this flow, installedOnEdit is run by the installable OnEdit trigger. When you use this, please check the checkbox. By this, installedOnEdit is run and CalendarApp.getDefaultCalendar() is run.
Note:
In this case, it supposes that your calendar() and the if statement in onEdit works fine. Please be careful this.
Reference:
Installable Triggers
Added:
I saw your provided sample Spreadsheet. When I saw it, the values of "Name", "Start Date", "End Date", "Add to Calendar" are the cells "B1:B4". But in your script, those values are not used. I think that your new issue is due to this. Please modify your script using your sample Spreadsheet as follows.
Modified script:
function calendar() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Course');
var start = new Date(spreadsheet.getRange('B2').getValue()).getTime();
var end = new Date(spreadsheet.getRange('B3').getValue()).getTime();
var name = spreadsheet.getRange('B1').getValue()
var calend = CalendarApp.getDefaultCalendar();
calend.createEvent(name, new Date(start), new Date(end));
}
function installedOnEdit(e) {
var rg = e.range;
if (rg.getA1Notation() === "B4" && rg.isChecked() && rg.getSheet().getName() === "Course") {
calendar(); //calling calendar function
rg.uncheck();
}
}
function installTrigger() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
ScriptApp.newTrigger("installedOnEdit").forSpreadsheet(ss).onEdit().create();
}
In this case, when the installable OnEdit trigger is installed by installTrigger(), when the checkbox of cell "B4" is checked, the event is created.

Related

Events are getting added to two default calendar - mine as well other users of the sheet

Here's the code which lets users to put details of events in cells and they tick the box and event gets added. The solution is put up by Mike Steelson.
Link - Add calendar event with the help of checkbox
function onOpen() {
SpreadsheetApp.getUi().createMenu('⇩ M E N U ⇩')
.addItem('👉 Set up ...', 'myTriggerSetup')
.addToUi();
}
function myTriggerSetup() {
var ssID = SpreadsheetApp.getActiveSpreadsheet().getId()
if (!isTrigger('onSpeEdit')) {
ScriptApp.newTrigger('onSpeEdit').forSpreadsheet(ssID).onEdit().create();
}
}
function isTrigger(funcName) {
var r = false;
if (funcName) {
var allTriggers = ScriptApp.getProjectTriggers();
var allHandlers = [];
for (var i = 0; i < allTriggers.length; i++) {
allHandlers.push(allTriggers[i].getHandlerFunction());
}
if (allHandlers.indexOf(funcName) > -1) {
r = true;
}
}
return r;
}
function onSpeEdit(e) {
var rg = e.range;
if (rg.getRow() == 4 && rg.isChecked() && rg.getSheet().getName() === "Course") {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Course');
var start = new Date(rg.offset(-2,0).getValue()).getTime();
var end = new Date(rg.offset(-1,0).getValue()).getTime();
var name = rg.offset(-3,0).getValue();
var calend = CalendarApp.getDefaultCalendar();
calend.createEvent(name, new Date(start), new Date(end));
rg.uncheck();
}
}
Issue:
Events are getting added to my default calendar as well as user's calendar too.
Requirement: It should get added to default calendar of the user who is entering details and clicking on the checkbox
Edit 1:.
Solution [1] by Mike.
var calendName = CalendarApp.getCalendarsByName('somebody')
I created a list on sheet with the names of default calendars of all users (like Alex Ab, John Cd, Ewel BM...) and changed the two lines of code this way but events were not getting added.
var calend = CalendarApp.getCalendarsByName('AA51')[0];
calend.createEvent(name, new Date(start), new Date(end));
Solution[2] = Duplicate sheet and trying. It did not work
Solution [3] = Adding macro to a button worked. Also, there is no need for a trigger with this. I feel very nervous with triggers as they stop working all of a sudden. Will it be a good idea to add a button instead?
I have added Mike Steelson's code to a button and it working nice.
Code for a button:.
function calendar() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Course');
var start = new Date(spreadsheet.getRange('U70').getValue()).getTime();
var end = new Date(spreadsheet.getRange('X69').getValue()).getTime();
var name = spreadsheet.getRange('U69').getValue()
var calend = CalendarApp.getDefaultCalendar();
calend.createEvent(name, new Date(start), new Date(end));
spreadsheet.getRange('X59').setValue('Hooray! Reminder is added to your calendar');
SpreadsheetApp.flush();
Utilities.sleep(5000);
spreadsheet.getRange('x59').clearContent();
}
May be 2 solutions
solution #1
create multiple agendas within your own agenda with the names of people,
then change a little the script as follows,
function onSpeEdit(e) {
var rg = e.range;
if (rg.getRow() == 4 && rg.isChecked() && rg.getSheet().getName() === "Course") {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Course');
var start = new Date(rg.offset(-2,0).getValue()).getTime();
var end = new Date(rg.offset(-1,0).getValue()).getTime();
var name = rg.offset(-3,0).getValue();
var calendName = CalendarApp.getCalendarsByName(rg.offset(1,0).getValue());
calendName[0].createEvent(name, new Date(start), new Date(end));
rg.uncheck();
}
}
and ask people to put their name as follows
you will get this
solution #2
ask everyone to copy the spreadsheet and thus create a new spreadsheet for them
if you need to synchronize use importrange
if you need to read, ask to share the agenda

Google Sheets run the script in all sheets

I am trying to implement the following function on Open sheet but I want to change the tab color on all the sheets. With this function, it allows me to change color only to single tab.
function getFirstEmptyRow() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetname = "Section A";
var sheet = ss.getSheetByName(sheetname);
var column = sheet.getRange('F:F');
var values = column.getValues(); // get all data in one call
var ct = 0;
while ( values[ct][0] != "" ) {
ct++;
}
Logger.log("Row "+ ct);
var ax=sheet.getRange(ct, 7).getValue();
if(ax == ""){
sheet.setTabColor("ff0000")
} else {
sheet.setTabColor(null)
}
}
Try this:
function onOpen() {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
sheets.forEach(s => s.setTabColor("ff0000"));
}
It hard to tell from the provided code, probably you need this:
function onOpen() {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
for (var sheet of sheets) {
var data = sheet.getDataRange().getValues(); // get all data
var col_G = data.map(x => x[6]); // get column G
var last_cell = col_G.pop(); // get last cell of column F
if (last_cell == '') sheet.setTabColor("ff0000");
}
}
Or even shorter:
function onOpen() {
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
for (var sheet of sheets) {
var data = sheet.getDataRange().getValues();
if (data.pop()[6] == '') sheet.setTabColor("ff0000");
}
}
It will make a tab red if in last row that of the table the cell in column G is empty.
If you have several sheets that you want to change you can filter them by names this way:
var names = ['Sheet1', 'Sheet2', 'Sheet3'];
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
sheets = sheets.filter(s => names.includes(s.getName()));
// the rest of a code
I'm assuming you want to change the tab color for all sheets if the value in column F of the last row of any sheet is blank. There are other values in that row. I've include onOPen, onEdit and onChange.
function onOpen(e) {
// onOpen is a simple trigger and doesn't need to be installed
// don't really use e in this scenario
getFirstEmptyRow();
}
function onEdit(e) {
// onEdit is a simple trigger and doesn't need to be installed
var sheet = e.range.getSheet();
if( e.range.getRow() === sheet.getDataRange().getLastRow() ) {
if( e.range.getColumn() === 6 ) {
if( e.value === "" ) getFirstEmptyRow();
}
}
}
function onChange(e) {
// onChange is an installed trigger
// don't really use e in this scenario
getFirstEmptyRow();
}
function getFirstEmptyRow() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
var i=0;
var sheet = null;
var value = null;
var color = null;
for( i=0; i<sheets.length; i++ ) {
sheet = sheets[i];
value = sheet.getRange(sheet.getDataRange().getLastRow(),7).getValue();
color = value === "" ? "ff0000" : null;
sheet.setTabColor(color);
}
}

Switching active sheet after "On Change" trigger

So I have an "on change" trigger set to activate this function so that it pulls the name of the tab that has just been created and puts it in a message box. Unfortunately when this is triggered after a new tab has been created it always treats the first tab in the spreadsheet as the active tab (i.e. 'Sheet1). Any ideas on how to to get it to switch the active sheet to the newly created tab?
function mynewFunction(e) {
if (e.changeType == 'INSERT_GRID') {
var ss = SpreadsheetApp.getActiveSheet().getName();
Browser.msgBox(ss);
}
}
The last sheet added via UI will be the last one, so you could get it with something like SpreadsheetApp.getActiveSpreadsheet().getSheets().pop().
You could then make it active with setActiveSheet():
function mynewFunction(e) {
if (e.changeType == 'INSERT_GRID') {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var lastSheet = spreadsheet.getSheets().pop();
spreadsheet.setActiveSheet(lastSheet);
Browser.msgBox(spreadsheet.getActiveSheet().getName());
}
}
Managed to figure out a workaround using by combining the use of script Properties, the "On Open" trigger, and the "On Change" trigger!
//Gets current list of sheets on open
function onOpened() {
var currentSheets = new Array();
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
for (var i=0 ; i<sheets.length ; i++) currentSheets.push(sheets[i].getName())
var currentSheets = currentSheets.join();
var updateProperties = PropertiesService.getScriptProperties();
updateProperties.setProperty('sheetsMaster', currentSheets);
}
//Displays name of new sheet on change
function onChanged(e) {
if (e.changeType == 'INSERT_GRID') {
var scriptProperties = PropertiesService.getScriptProperties().getProperties();
var sheetsMaster = scriptProperties.sheetsMaster;
var oldList = sheetsMaster.split(",");
var newList = new Array();
var changedSheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
for (var i=0 ; i<changedSheets.length ; i++) newList.push(changedSheets[i].getName())
for (var i=0 ; i<newList.length ; i++){
if (newList[i] != oldList[i]) {
//Displays newly added sheet name
Browser.msgBox(newList[i]);
//Updates list to reflect change
oldList.splice(i,0,newList[i]);
var setNewProperties = PropertiesService.getScriptProperties();
setNewProperties.setProperty('sheetsMaster', oldList.join());
return;
}
}
}
}

Installable trigger created using "ScriptApp.newTrigger" has to be re-saved before it will run

I have an Expenses sheet that I copy to the Google Drive folder for each of my relevant users. Each copy of the sheet needs an installable trigger that calls a function to insert additional rows when the last row of data gets edited. These are triggered using the onEdit event. The installable triggers work fine when created manually (via "Edit Current Project's triggers").
To simplify the process of setting up new users, I have scripted the creation of my trigger. Although the script creates the trigger and it appears exactly the same as the manually created one, it only works if I manually open up the trigger, re-select the function to trigger and re-save it.
I can confirm I am the owner when running the creation script.
The behaviour I'm seeing suggests to me that there is something incorrect with the function name in my script however it all looks fine to me. I'd really appreciate some help with this....
function createInsertRowsTrigger(){
Logger.log('Id='+ss.getId());
createInstallableTrigger("onEditOfLastRow",ss.getId());
}
function createInstallableTrigger(funcName,ssId) {
if(!isTrigger(funcName)) {
ScriptApp.newTrigger(funcName).forSpreadsheet(ssId).onEdit().create();
}
}
function isTrigger(funcName){
Logger.log('In isTrigger');
var r=false;
if(funcName){
Logger.log('Function found');
var allTriggers=ScriptApp.getProjectTriggers();
for(var i=0;i<allTriggers.length;i++){
if(funcName==allTriggers[i].getHandlerFunction()){
r=true;
Logger.log('trigger already exists');
break;
}
}
}
return r;
}
The full code is here....
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('SCLGA Expenses Menu')
.addItem('Approve Expenses', 'ApproveExpenses')
.addToUi();
resetValidationRules();
}
//===========================================================================================
// global
var ss = SpreadsheetApp.getActive();
//===========================================================================================
function onEditofLastRow(e) {
var value = ss.getActiveSheet().getRange(3, 6).getValue();// row number of the last but one row
editedCol =e.range.getSheet().getActiveCell().getColumn();
editedRow =e.range.getSheet().getActiveCell().getRow();
// if the last cell in the last row is edited...create some more rows...
if(editedCol==7 && editedRow== value-1){
showAlert('Looks like you need some more rows... ');
insertRows();
}
}
function createInsertRowsTrigger(){
Logger.log('Id='+ss.getId());
createInstallableTrigger("onEditOfLastRow",ss.getId());
}
function createInstallableTrigger(funcName,ssId) {
if(!isTrigger(funcName)) {
ScriptApp.newTrigger(funcName).forSpreadsheet(ssId).onEdit().create();
}
}
function isTrigger(funcName){
Logger.log('In isTrigger');
var r=false;
if(funcName){
Logger.log('Function found');
var allTriggers=ScriptApp.getProjectTriggers();
for(var i=0;i<allTriggers.length;i++){
if(funcName==allTriggers[i].getHandlerFunction()){
r=true;
Logger.log('trigger already exists');
break;
}
}
}
return r;
}
function showAlert(msg) {
var ui = SpreadsheetApp.getUi();
var result = ui.alert(msg);
}
function insertRows() {
// this function inserts some new rows and copies relevant formulas and formats
// this value tells us where the next data section starts
var value = ss.getActiveSheet().getRange(3, 6).getValue();
var rowsToAdd = 5;
var firstRow = value-rowsToAdd;
var sh = ss.getActiveSheet();
var lCol = sh.getLastColumn();
var range = sh.getRange(firstRow, 1, rowsToAdd, lCol);
// copy formulas
var formulaRange1 = sh.getRange(firstRow, 1, rowsToAdd, 1);
var formulaRange2 = sh.getRange(firstRow, 8, rowsToAdd, lCol-8);
var formulas1 = formulaRange1.getFormulasR1C1();
var formulas2 = formulaRange2.getFormulasR1C1();
// insert rows
sh.insertRowsAfter(firstRow+rowsToAdd-1, rowsToAdd);
// define new range
newRange1 = sh.getRange(firstRow+rowsToAdd, 1, rowsToAdd, 1);
newRange2 = sh.getRange(firstRow+rowsToAdd, 8, rowsToAdd, lCol-8);
// set formulas
newRange1.setFormulasR1C1(formulas1);
newRange2.setFormulasR1C1(formulas2);
// copy formatting for range 2
range.copyFormatToRange(sh, 1, lCol-8, firstRow+rowsToAdd, firstRow+rowsToAdd+rowsToAdd-1);
resetValidationRules();
resetTransactionUploadFormulas();
}
function resetTransactionUploadFormulas(){
var sheet = ss.getSheetByName('Transactions to load');
sourceFormulas = sheet.getRange(2,1,1,12).getFormulasR1C1();
for (i=3; i<=250; i++)
newRange=sheet.getRange(i,1,1,12).setFormulasR1C1(sourceFormulas);
}
function resetValidationRules(){
var value = ss.getActiveSheet().getRange(3, 6).getValue();
var firstRow = 5;
var sh = ss.getActiveSheet();
var lCol = sh.getLastColumn();
var range = sh.getRange(firstRow, 1, 245, lCol);
// Apply validation rules to all rows
for(i = 1; i <= 250; i++){
currentRowNumber = 4+i;
var cell = SpreadsheetApp.getActive().getRange('F'+currentRowNumber);
var eventRange = sh.getRange("L"+currentRowNumber+":BB"+currentRowNumber)
var rule = SpreadsheetApp.newDataValidation().requireValueInRange(eventRange).build();
if (value != currentRowNumber && value+1 != currentRowNumber)
cell.setDataValidation(rule);
}
}

Google Apps Script - Make onEdit() recognize setValue() changes

I have a Spreadsheet with some functions. One of them is a onEdit(event) function that copies some values to other sheets based on conditions. This is the code (simplified but with the important parts intact):
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.range;
if(s.getName() === "Lista" && r.getColumn() === 9 && r.getValue() === "Posicionada") {
var sheetname = s.getRange(r.getRow(),3).getValue();
var columnRef = s.getRange(r.getRow(),4).getValue();
var row = s.getRange(r.getRow(),5).getValue();
var targetSheet = ss.getSheetByName("Mapa " + sheetname);
var headers = targetSheet.getRange(1, 1, 1, targetSheet.getLastColumn());
for (var i = 0; i < headers; i++) {
if (headers[i] === columnRef) {
break;
}
}
var column;
if (columnRef === "A1") {
column = 2;
}
else if (columnRef === "A2") {
column = 3;
}
else if (columnRef === "B1") {
column = 4;
}
else if (columnRef === "B2") {
column = 5;
}
if (sheetname === "N2") {
row = row - 30;
}
if (sheetname === "N3") {
column = column - 10;
row = row - 42;
}
targetSheet.getRange(row,column).setValue(s.getRange(r.getRow(), 1, 1, 1).getValue());
}
}
The code works as it should when I manually edit the cell. But, I have a code that edit the cell when the user press a button in a sidebar, this is the code:
function positionMU(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var cell = ss.getActiveCell().activate();
var cellLevel = cell.offset(0,2);
var cellLetter = cell.offset(0,3);
var cellNumber = cell.offset(0,4);
var cellStatus = cell.offset(0,8);
var dbq = "Posicionada";
var fora = "Pendente de recebimento";
if (cellStatus.getValue() == "Aguardando posicionamento"){
cellStatus.setValue(dbq); //attention in this line
}
else if (cellStatus.getValue() == "Aguardando saída"){
cellStatus.setValue(fora);
var cellExitDate = cell.offset(0,6);
cellExitDate.setValue(getDate());
}
}
As you can see, this function change the cell content with setValue(), but, when I use this function, the value of the cell changes, but the onEdit() trigger doesn't work.
How can I make the onEdit() trigger recognize changes made with setValue()?
You are right. onEdit() only triggers if the range is edited manually. As can be seen here, onEdit() triggers when a value is changed by the user.
I tested the function by making function to insert values into a column for which my onEdit responds and nothing happens. Including various other techniques that I could think of. Best thing to do here is to suggest this as an enhancement on App Script's Issue Tracker.
However, I made it work by writing another function to be called when another function in the script makes changes to the sheet. These are the test functions I wrote:
function addValues()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var range = sheet.getDataRange();
var book = "Book";
var cancel = "Cancel";
var maxRow = range.getLastRow()+1;
for(var i=0; i<4; i++)
{
if (i%2 == 0)
{
sheet.getRange(maxRow, 1).setValue(book);
autoChanges(maxRow);
}else{
sheet.getRange(maxRow, 1).setValue(cancel);
autoChanges(maxRow);
}
maxRow++;
}
}
autoChanges function:
function autoChanges(row)
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var range = sheet.getDataRange();
var data = range.getValues();
var response = "";
sheet.getRange(row, 2).protect();
response = data[row-1][0];
if (response == "Book")
{
sheet.getRange(row, 2).canEdit();
}else{
sheet.getRange(row, 2).setValue("--NA--");
}
}
Not the most elegant solution but this seems to be the only workaround for what you are trying to do.
There are some very good reasons why calling range.setValue() doesn't trigger the onEdit event, and most of them have to do with infinite recursion. In fact, you call setValue() yourself WITHIN onEdit(). This would trigger a recursive call, and from what I can see, you have no provision for handling the base case and thus your code would explode if setValue() did what you want.
Why not simply take all of your code out of your event handler, and put it into another function:
function onEdit (e) {
return handleEdits(e.range);
}
function handleEdits(r) {
s = r.getSheet();
ss = s.getParent();
//the rest of your code should drop right in.
}
then, inside your autoChanges function, go ahead and call handleEdits, passing it an appropriate range, after your call to setValue().
If you like to play with fire, and I personally do, you can call the onEdit(e) function after you make a change. Just send in an object whatever is called and used by the e object.
For me, I just needed to add:
var e={};
e.range=the range you are making a change to in the script;
e.source = SpreadsheetApp.getActiveSpreadsheet();//or make sure you have the sheet for wherever you are setting the value
e.value=whatever value you are setting
e.oldValue=if you onEdit needs this, set it here
//if you are using any of the other standard or special properties called by your onEdit...just add them before calling the function.
onEdit(e);//call the function and give it what it needs.