-1

I use this in a very small business. We sale the aggregates E Column and the items(DUST,6MM,10MM,20MM,40MM) and quantity F Column are listed (1 ,2 3, 4, 5,6) in drop down. So the Range E7:F300 are Unprotected, rest all the cells are protected for the users.

The users select the Item and Quantity in a day and those cells should be auto protected to that user and all other users at specific time. Say night around 10:00pm. It should protect only Non Empty cell but not the entire Range. I am new to this Script, Can anyone help me out with the script as per my requirement?

11
  • 1
    Welcome. Please add a brief description of your search/research efforts as is suggested in How to Ask. May 2, 2020 at 21:42
  • Welcome. It is helpful to understand how this requirement is used in your business. May I try to clarify? please correct me if I am wrong. When some aggregate is issued for a customer, the user goes to the next new line in the spreadsheet and selects the type in Column E, and the quantity in Column F. As the day goes on, users record more transactions in rows of Column E&F. You don't want the cells to be protected as the data is entered, you want to wait until the end of the day, say at 10pm. At that time, you want all the non-blank cells in Column E & F to be protected. Is that right?
    – Tedinoz
    May 3, 2020 at 0:00
  • Thank You Mr. Ruben for replying me. you have understood my question.Yes the user goes to the next line and select the aggregate and quantity from E and F Column.yes I dont want those selected cells to be protected immediately because if they do wrong selection and they cant correct if that cells locked immediately. So I want all those non-blank cells in Column E & F to be protected at 10:00 pm. I Kept E7:F300 Unprotected. if 1st day if they select from E7:F13 at night those cells should be protected 2nd day if they select E14:F17 at night those cells should be protected.
    – Srinivas
    May 3, 2020 at 8:12
  • 1
    This is a fairly common topic that would have come up in your research, as @Rubén asked your to describe.Is there a reason that you have not applied one of the many topics on this the same subect?
    – Tedinoz
    May 3, 2020 at 11:54
  • 1
    Does this answer your question? Lock a Google Sheet after 00:00
    – Tedinoz
    May 3, 2020 at 11:54

1 Answer 1

0

You want to protect cells containing content in the range E7:G150 on "sheet="CASH SALE" and range I6:L404 on sheet="HOPPER" at 10:00pm each night.

Locking cells in Google Sheets at a specific time (by @Punchlinernon on StackOverflow) provides a good basis for your solution. However your scenario is different because the range to be protected is extended each day. One result is that there would be a protected ranges created every night - over time many dozens of protected ranges would be unnecessarily/unproductively created. So the first step is to remove the protected range then protect the entire range of content. The result is a single protected range.

Functions

  • lockRanges(): this is the primary function that should be assigned to the trigger. This contains the data for each of the relevant sheets and passes processing to the sub-routine locksub().

  • locksub(sheetname, row, col, numCol): this is the main processing function. Data is passed from lockranges(). It relies on a single utility columnToLetter() to produce the range to be protected.

  • columnToLetter(column): converts a column number to a letter. This is used to define a range.

Key Points

  • var sheetname = "Transactions"; - used for the sheet name, but also used for the description of the protected range.
  • var sheet = ss.getSheetByName(sheetname); - added to ensure that the changes are made to a specific sheet
  • if (protections[i].getDescription() == sheetname) { - a test to check if there is already a protected range with the target description, if yes, then the range is unprotected.
  • var lastRow = sheet.getLastRow(); - this returns the last row containing content and is used to define the protected range.
  • if( row <= lastRow){ - a test to make sure that there is content; if no content then no action taken
  • var range = sheet.getRange(row, col,numrows,numCol); - the range to be protected; variables are used for every attribute. The Range starts at row 7 of Column E and extending to the last row of content in Column F.
  • var protection = range.protect().setDescription(sheetname); - protects the range, and assigns the description.

Props - @AdamL for columnToLetter


function lockRanges() {

  // this sheet carries the data for the ranges to be adusted
  // and passes this for execution to sub routine = logsub
  var ss = SpreadsheetApp.getActiveSpreadsheet();

  // data for CASH SALE
  var sheetname = "CASH SALE";
  //cell variables
  var row = 7; // row 7
  var col = 5; // column E
  var numCol = 3; // Column E, F and G
  locksub(sheetname, row, col, numCol);
  Logger.log("finished lockranges")


  // data for HOPPER
  var sheetname = "HOPPER";
  //cell variables
  var row = 6; //row 6
  var col = 9; // column I
  var numCol = 4; // Column I, K, K and L
  locksub(sheetname, row, col, numCol);
  Logger.log("finished lockranges")

  return;

}

function locksub(sheetname, row, col, numCol){

  // subroutine called from lockRanges
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName(sheetname);

  /*
  a new protected range is run for eavery time the script is run
  so, test for an existing description and delete it
  then run the rest of the script
  the result should be a single protected range
  */
  var protections = sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
  for (var i = 0; i < protections.length; i++) {
    var protection = protections[i];
    Logger.log("DEBUG: protected range = "+protection.getRange().getA1Notation()+", name = "+protection.getDescription());
    if (protection.canEdit()) {
      if (protections[i].getDescription() == sheetname) {
        Logger.log("DEBUG: this protection is named "+sheetname)
        protections[i].remove();
      }
    }
  }

  // get the data range
  var celladdress = sheet.getRange(row, col).getA1Notation();
  var colLetter = columnToLetter(col)
  var datarange = celladdress+":"+colLetter;
  // Logger.log("DEBUG: the datarange is "+datarange)
  var Evals = ss.getRange(datarange).getValues();
  var Elast = Evals.filter(String).length;
  // Logger.log("DEBUG: Number of rows of content = "+Elast)
  var numrows = Elast;
  if( Elast>=1){
    // define the range
    var range = sheet.getRange(row, col,numrows,numCol);
    // Logger.log("DEBUG: the range is "+range.getA1Notation())


    // Lock current range
    // Create protection object. Set description, anything you like.
    var protection = range.protect().setDescription(sheetname);

    // Ensure the current user is an editor before removing others. Otherwise, if the user's edit
    // permission comes from a group, the script will throw an exception upon removing the group.
    var me = Session.getEffectiveUser();
    protection.addEditor(me)
    protection.removeEditors(protection.getEditors());
    if (protection.canDomainEdit()) {
      protection.setDomainEdit(false);
    }
  }

  Logger.log("finished locksub")
return;
}

function columnToLetter(column){
  var temp, letter = '';
  while (column > 0){
    temp = (column - 1) % 26;
    letter = String.fromCharCode(temp + 65) + letter;
    column = (column - temp - 1) / 26;
  }
  return letter;
}
20
  • Thank Q @Tedinoz ,I checked with the script . Its Working Fine. here if the user jumps from 16th row to 25th row then the whole empty cells get protected. however user is not permitted to Jump the empty rows. well the script fulfill my need. How If I need three more Column in the same sheet to be protected. Like you did with E and F and I Need W X and Y Column to be protected same way.
    – Srinivas
    May 14, 2020 at 19:26
  • @Srinivas Regarding a user jumping empty rows, I find that a sound thrashing works well to modify user habits; the alternative for the script is to loop through the column and apply protection where a cell has a value. BUT as you get more rows of data, you would create hundreds of protected cell ranges versus just a single range by this script - it's up to you. Regarding three more columns: edit the script to do columns E and F (as written, then duplicate the relevant part of the script to do the second range of three rows. Either than, or create a sub-routine for the repetition.
    – Tedinoz
    May 15, 2020 at 2:00
  • Thank Q @Tedinoz. The Script is Really Helpful . I Will Use this Script. For my second range of three rows I Will Create another script file and change the var row = 24; var col = 5; var numCol = 3 ; Column and row . Thanks Once again
    – Srinivas
    May 15, 2020 at 18:40
  • @Srinivas A few things for the new range: the script still needs to be on a time-driven trigger; you'll want to remove the protection (based on a description??) (maybe create a new variable for the name?) and "col" ought to be 24 (Column X). BTW, if the answer works for you, them you might also consider "accepting" it.
    – Tedinoz
    May 16, 2020 at 0:40
  • 1
    The updated script is quite different, and it contains three functions as described in the answer.Basically you enter your sheet and some range data in lockranges, and the sub-routines look after the rest. So lockranges is the function to put in the time-driven installable trigger. Your notes also refer to protection of a range "AA6 To AC36" on Hopper but the parameters for this are different to the other two ranges, so you should apply what you have learned here to develop a script for that range. If this answer has been useful, please accept it.
    – Tedinoz
    May 19, 2020 at 2:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.