From 877d2544bff28edfb1ec65e4b84c4e8b588a9976 Mon Sep 17 00:00:00 2001
From: suomiy
Date: Wed, 15 Dec 2021 21:40:46 +0100
Subject: [PATCH 01/26] introduce number of rows for weekdays/weekend for new
groups
- display number of rows per group in groups list
---
src/Billing/appsscript.json | 2 +-
src/CalendarAndFilesScheduler/appsscript.json | 2 +-
src/Create/appsscript.json | 2 +-
src/Create/group-form.html | 12 ++++++++++++
src/Create/group.js | 16 ++++++++++++++--
src/Delete/appsscript.json | 2 +-
src/EmailSender/appsscript.json | 2 +-
src/PdfBackuper/appsscript.json | 2 +-
src/RenameGroup/appsscript.json | 2 +-
src/SheetRedirect/appsscript.json | 2 +-
src/Statistics/appsscript.json | 2 +-
src/TableScript/Groups.js | 10 +++++++---
src/TableScript/appsscript.json | 2 +-
src/Update/appsscript.json | 2 +-
src/Utils/Validator.js | 5 +++++
15 files changed, 49 insertions(+), 16 deletions(-)
diff --git a/src/Billing/appsscript.json b/src/Billing/appsscript.json
index 2c0e29d..a277eef 100644
--- a/src/Billing/appsscript.json
+++ b/src/Billing/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 33
+ "version": 34
}
]
},
diff --git a/src/CalendarAndFilesScheduler/appsscript.json b/src/CalendarAndFilesScheduler/appsscript.json
index 98f2830..2de1cee 100644
--- a/src/CalendarAndFilesScheduler/appsscript.json
+++ b/src/CalendarAndFilesScheduler/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 33
+ "version": 34
}
]
},
diff --git a/src/Create/appsscript.json b/src/Create/appsscript.json
index 2c0e29d..a277eef 100644
--- a/src/Create/appsscript.json
+++ b/src/Create/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 33
+ "version": 34
}
]
},
diff --git a/src/Create/group-form.html b/src/Create/group-form.html
index 969ffd8..10c6fb7 100644
--- a/src/Create/group-form.html
+++ b/src/Create/group-form.html
@@ -5,3 +5,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Create/group.js b/src/Create/group.js
index aedb737..1f00c47 100644
--- a/src/Create/group.js
+++ b/src/Create/group.js
@@ -6,16 +6,28 @@
* @throws Exception if creating Group failed
*/
function processGroupObj(formObject) {
- var errorMsg = {groupErr:''};
+ var errorMsg = {groupErr:'', weekdayRowsErr: '', weekendRowsErr: ''};
var groups = Utils.findGroupsAsArray();
var group = {};
- group.group = Utils.validate(errorMsg,formObject.groupBox,{
+ group.group = Utils.validate(errorMsg, formObject.groupBox, {
actions:['trim','notNull','unique','length'],
actionObjs:[{},{},{uniqueArray:groups},{length:10}],
actionErrors:[{},{groupErr:'*vyplňte skupinu'},{groupErr:'*jméno této skupny není unikátní'},{groupErr:'*tato skupina má více než 10 znaků'}]
});
+ group.weekdayRows = Utils.validate(errorMsg, formObject.weekdayRowsBox, {
+ actions:['notNull','isPositiveNumber'],
+ actionObjs:[{},{}],
+ actionErrors:[{weekdayRowsErr:'*vyplňte počet řádků'},{weekdayRowsErr:'*vyplňte pozitivní číslo'}]
+ });
+
+ group.weekendRows = Utils.validate(errorMsg, formObject.weekendRowsBox, {
+ actions:['notNull','isPositiveNumber'],
+ actionObjs:[{},{}],
+ actionErrors:[{weekendRowsErr:'*vyplňte počet řádků'},{weekendRowsErr:'*vyplňte pozitivní číslo'}]
+ });
+
Utils.validate(errorMsg,Utils.AccessEnums.GROUP,{
actions:['canEdit'],
actionObjs:[{}],
diff --git a/src/Delete/appsscript.json b/src/Delete/appsscript.json
index 2c0e29d..a277eef 100644
--- a/src/Delete/appsscript.json
+++ b/src/Delete/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 33
+ "version": 34
}
]
},
diff --git a/src/EmailSender/appsscript.json b/src/EmailSender/appsscript.json
index 2c0e29d..a277eef 100644
--- a/src/EmailSender/appsscript.json
+++ b/src/EmailSender/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 33
+ "version": 34
}
]
},
diff --git a/src/PdfBackuper/appsscript.json b/src/PdfBackuper/appsscript.json
index 2c0e29d..a277eef 100644
--- a/src/PdfBackuper/appsscript.json
+++ b/src/PdfBackuper/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 33
+ "version": 34
}
]
},
diff --git a/src/RenameGroup/appsscript.json b/src/RenameGroup/appsscript.json
index 8a0859e..b5a864a 100644
--- a/src/RenameGroup/appsscript.json
+++ b/src/RenameGroup/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 33
+ "version": 34
}
]
},
diff --git a/src/SheetRedirect/appsscript.json b/src/SheetRedirect/appsscript.json
index 2c0e29d..a277eef 100644
--- a/src/SheetRedirect/appsscript.json
+++ b/src/SheetRedirect/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 33
+ "version": 34
}
]
},
diff --git a/src/Statistics/appsscript.json b/src/Statistics/appsscript.json
index 2c0e29d..a277eef 100644
--- a/src/Statistics/appsscript.json
+++ b/src/Statistics/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 33
+ "version": 34
}
]
},
diff --git a/src/TableScript/Groups.js b/src/TableScript/Groups.js
index a0fb30e..c2692fe 100644
--- a/src/TableScript/Groups.js
+++ b/src/TableScript/Groups.js
@@ -4,15 +4,17 @@
*
* @return dataTable object or empty object
*/
-function getGroupsTable() {
+ function getGroupsTable() {
if (!Utils.hasAccessTo(Utils.AccessEnums.GROUP,Utils.PermissionTypes.VIEW)) {
return {};
}
- var groups = Utils.sort(Utils.findGroupsAsArray());
+ var groups = Utils.sort(Utils.findGroups(), 'group');
var dt = {
cols:[
{id:0, label:'Skupina', type: 'string', stringFilter: 'true'},
+ {id:0, label:'Počet řádků ve všední den', type: 'number'},
+ {id:0, label:'Počet řádků o víkendu', type: 'number'},
],
rows:[]
};
@@ -20,7 +22,9 @@ function getGroupsTable() {
for(var i = 0; i < groups.length; i++) {
dt.rows.push({
c:[
- {v: groups[i]},
+ {v: groups[i].group},
+ {v: groups[i].weekdayRows},
+ {v: groups[i].weekendRows},
]
});
}
diff --git a/src/TableScript/appsscript.json b/src/TableScript/appsscript.json
index 2c0e29d..a277eef 100644
--- a/src/TableScript/appsscript.json
+++ b/src/TableScript/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 33
+ "version": 34
}
]
},
diff --git a/src/Update/appsscript.json b/src/Update/appsscript.json
index 2c0e29d..a277eef 100644
--- a/src/Update/appsscript.json
+++ b/src/Update/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 33
+ "version": 34
}
]
},
diff --git a/src/Utils/Validator.js b/src/Utils/Validator.js
index 95454a5..40d5e03 100644
--- a/src/Utils/Validator.js
+++ b/src/Utils/Validator.js
@@ -76,6 +76,11 @@ function validate(errorResult, input, processObj) {
setError_(errorResult, actionErrors[i]);
}
break;
+ case 'isPositiveNumber':
+ if (isNaN(input) || input < 1) {
+ setError_(errorResult, actionErrors[i]);
+ }
+ break;
case 'isNotDatabaseOwner':
if (isMainAdmin(input)) {
setError_(errorResult, actionErrors[i]);
From 614d85396c14e58a466ff83a06694e036ef0cd90 Mon Sep 17 00:00:00 2001
From: suomiy
Date: Wed, 15 Dec 2021 22:37:32 +0100
Subject: [PATCH 02/26] implement group update
---
src/Update/Code.js | 7 +++++
src/Update/Utils.js | 7 +++++
src/Update/group-form.html | 21 +++++++++++++++
src/Update/group.js | 55 ++++++++++++++++++++++++++++++++++++++
src/Update/javascript.html | 3 +++
5 files changed, 93 insertions(+)
create mode 100644 src/Update/group-form.html
create mode 100644 src/Update/group.js
diff --git a/src/Update/Code.js b/src/Update/Code.js
index 6c8538b..2a62916 100644
--- a/src/Update/Code.js
+++ b/src/Update/Code.js
@@ -29,6 +29,11 @@ function doGet(e) {
shortcut: e.parameter.shortcut
})[0];
break;
+ case 'group':
+ opts.updateObj = Utils.findGroups([], {
+ group: e.parameter.group
+ })[0];
+ break;
default:
return createPresentableHTML('Authorizace...OK
', 'string');
break;
@@ -59,6 +64,8 @@ function processForm(formObject) {
return processClientObj(formObject, opts);
case 'tariff':
return processTariffObj(formObject, opts);
+ case 'group':
+ return processGroupObj(formObject, opts);
default:
return null;
}
diff --git a/src/Update/Utils.js b/src/Update/Utils.js
index a42fdea..e6800e6 100644
--- a/src/Update/Utils.js
+++ b/src/Update/Utils.js
@@ -32,6 +32,13 @@ function getResource(resource, opts) {
default:
return null;
}
+ case 'group':
+ switch (resource) {
+ case 'form':
+ return includeAndEvaluate('group-form', opts);
+ default:
+ return null;
+ }
default:
return null;
}
diff --git a/src/Update/group-form.html b/src/Update/group-form.html
new file mode 100644
index 0000000..fc8bb62
--- /dev/null
+++ b/src/Update/group-form.html
@@ -0,0 +1,21 @@
+
+
+ var group = updateObj ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Update/group.js b/src/Update/group.js
new file mode 100644
index 0000000..4d807c5
--- /dev/null
+++ b/src/Update/group.js
@@ -0,0 +1,55 @@
+/**
+ * Parses and validates data from formObject, then it updates Group.
+ *
+ * @param formObject Object received from client's browser form.
+ * @param {Object} opts received URL params and loaded data
+ * @return {Object} object which designates success or failure (in a case form had nonvalid data)
+ * @throws Exception if updating Group failed
+ */
+function processGroupObj(formObject, opts) {
+ var errorMsg = { groupErr:'', weekdayRowsErr: '', weekendRowsErr: '' };
+ var oldGroup = opts.updateObj;
+ var group = { group: oldGroup.group };
+
+
+ if (formObject.weekdayRowsBox == oldGroup.weekdayRows) {
+ group.weekdayRows = oldGroup.weekdayRows;
+ } else {
+ group.weekdayRows = Utils.validate(errorMsg, formObject.weekdayRowsBox, {
+ actions:['notNull','isPositiveNumber'],
+ actionObjs:[{},{}],
+ actionErrors:[{weekdayRowsErr:'*vyplňte počet řádků'},{weekdayRowsErr:'*vyplňte pozitivní číslo'}]
+ });
+ }
+
+ if (formObject.weekendRowsBox == oldGroup.weekendRows) {
+ group.weekendRows = oldGroup.weekendRows;
+ } else {
+ group.weekendRows = Utils.validate(errorMsg, formObject.weekendRowsBox, {
+ actions:['notNull','isPositiveNumber'],
+ actionObjs:[{},{}],
+ actionErrors:[{weekendRowsErr:'*vyplňte počet řádků'},{weekendRowsErr:'*vyplňte pozitivní číslo'}]
+ });
+ }
+
+ Utils.validate(errorMsg,Utils.AccessEnums.GROUP,{
+ actions:['canEdit'],
+ actionObjs:[{}],
+ actionErrors:[{groupErr:'*nemáte oprávnění pro tento typ akce'}]
+ });
+
+ if (Utils.isObjErrorFree(errorMsg)) {
+ if (!shallowEquals_(group, oldGroup)) {
+ if (Utils.updateGroup(group, oldGroup.group)) {
+ errorMsg.success = 'Skupina uspěšně změněna.';
+ errorMsg.permission = Utils.AccessEnums.SCHEDULE;
+ } else {
+ throw {message:'updateGroup'};
+ }
+ } else {
+ errorMsg.success = 'Skupina nebyla změněna.';
+ }
+ }
+
+ return errorMsg;
+}
diff --git a/src/Update/javascript.html b/src/Update/javascript.html
index e0ab9eb..bc7474c 100644
--- a/src/Update/javascript.html
+++ b/src/Update/javascript.html
@@ -68,6 +68,9 @@
case 3:
$('#confirmationSpecial').text('\nK nabytí daných práv dojde nejzpoději do 2 hodin.\n\nV akutním případě kontaktujte main admina.');
break;
+ case 505:
+ alert('Bude aplikováno pro rozpisy za 3 měsíce! Pouze nové rozpisy budou vytvořeny s tímto počtem řádků. Pro rychlejší změnu kontaktujte main admina.');
+ break;
}
}
From b7c7f834d8e1cf234817aec7297ccc2705c439ff Mon Sep 17 00:00:00 2001
From: suomiy
Date: Wed, 15 Dec 2021 23:50:09 +0100
Subject: [PATCH 03/26] set maximum number of rows 150 per day
---
src/Billing/appsscript.json | 2 +-
src/CalendarAndFilesScheduler/appsscript.json | 2 +-
src/Create/appsscript.json | 2 +-
src/Create/group-form.html | 4 ++--
src/Create/group.js | 12 ++++++------
src/Delete/appsscript.json | 2 +-
src/EmailSender/appsscript.json | 2 +-
src/PdfBackuper/appsscript.json | 2 +-
src/RenameGroup/appsscript.json | 2 +-
src/SheetRedirect/appsscript.json | 2 +-
src/Statistics/appsscript.json | 2 +-
src/TableScript/appsscript.json | 2 +-
src/Update/appsscript.json | 2 +-
src/Update/group-form.html | 4 ++--
src/Update/group.js | 12 ++++++------
src/Utils/Validator.js | 5 +++++
16 files changed, 32 insertions(+), 27 deletions(-)
diff --git a/src/Billing/appsscript.json b/src/Billing/appsscript.json
index a277eef..341e836 100644
--- a/src/Billing/appsscript.json
+++ b/src/Billing/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 34
+ "version": 35
}
]
},
diff --git a/src/CalendarAndFilesScheduler/appsscript.json b/src/CalendarAndFilesScheduler/appsscript.json
index 2de1cee..2fa51a1 100644
--- a/src/CalendarAndFilesScheduler/appsscript.json
+++ b/src/CalendarAndFilesScheduler/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 34
+ "version": 35
}
]
},
diff --git a/src/Create/appsscript.json b/src/Create/appsscript.json
index a277eef..341e836 100644
--- a/src/Create/appsscript.json
+++ b/src/Create/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 34
+ "version": 35
}
]
},
diff --git a/src/Create/group-form.html b/src/Create/group-form.html
index 10c6fb7..32b7ab6 100644
--- a/src/Create/group-form.html
+++ b/src/Create/group-form.html
@@ -8,12 +8,12 @@
-
+
-
+
diff --git a/src/Create/group.js b/src/Create/group.js
index 1f00c47..3cba9fc 100644
--- a/src/Create/group.js
+++ b/src/Create/group.js
@@ -17,15 +17,15 @@ function processGroupObj(formObject) {
});
group.weekdayRows = Utils.validate(errorMsg, formObject.weekdayRowsBox, {
- actions:['notNull','isPositiveNumber'],
- actionObjs:[{},{}],
- actionErrors:[{weekdayRowsErr:'*vyplňte počet řádků'},{weekdayRowsErr:'*vyplňte pozitivní číslo'}]
+ actions:['notNull','isPositiveNumber', 'max'],
+ actionObjs:[{},{},{ max: 150 }],
+ actionErrors:[{weekdayRowsErr:'*vyplňte počet řádků'},{weekdayRowsErr:'*vyplňte pozitivní číslo'}, {weekdayRowsErr:'*počet řádků by neměl převyšovat 150'}]
});
group.weekendRows = Utils.validate(errorMsg, formObject.weekendRowsBox, {
- actions:['notNull','isPositiveNumber'],
- actionObjs:[{},{}],
- actionErrors:[{weekendRowsErr:'*vyplňte počet řádků'},{weekendRowsErr:'*vyplňte pozitivní číslo'}]
+ actions:['notNull','isPositiveNumber', 'max'],
+ actionObjs:[{},{},{ max: 150 }],
+ actionErrors:[{weekendRowsErr:'*vyplňte počet řádků'},{weekendRowsErr:'*vyplňte pozitivní číslo'}, {weekendRowsErr:'*počet řádků by neměl převyšovat 150'}]
});
Utils.validate(errorMsg,Utils.AccessEnums.GROUP,{
diff --git a/src/Delete/appsscript.json b/src/Delete/appsscript.json
index a277eef..341e836 100644
--- a/src/Delete/appsscript.json
+++ b/src/Delete/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 34
+ "version": 35
}
]
},
diff --git a/src/EmailSender/appsscript.json b/src/EmailSender/appsscript.json
index a277eef..341e836 100644
--- a/src/EmailSender/appsscript.json
+++ b/src/EmailSender/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 34
+ "version": 35
}
]
},
diff --git a/src/PdfBackuper/appsscript.json b/src/PdfBackuper/appsscript.json
index a277eef..341e836 100644
--- a/src/PdfBackuper/appsscript.json
+++ b/src/PdfBackuper/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 34
+ "version": 35
}
]
},
diff --git a/src/RenameGroup/appsscript.json b/src/RenameGroup/appsscript.json
index b5a864a..aee925f 100644
--- a/src/RenameGroup/appsscript.json
+++ b/src/RenameGroup/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 34
+ "version": 35
}
]
},
diff --git a/src/SheetRedirect/appsscript.json b/src/SheetRedirect/appsscript.json
index a277eef..341e836 100644
--- a/src/SheetRedirect/appsscript.json
+++ b/src/SheetRedirect/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 34
+ "version": 35
}
]
},
diff --git a/src/Statistics/appsscript.json b/src/Statistics/appsscript.json
index a277eef..341e836 100644
--- a/src/Statistics/appsscript.json
+++ b/src/Statistics/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 34
+ "version": 35
}
]
},
diff --git a/src/TableScript/appsscript.json b/src/TableScript/appsscript.json
index a277eef..341e836 100644
--- a/src/TableScript/appsscript.json
+++ b/src/TableScript/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 34
+ "version": 35
}
]
},
diff --git a/src/Update/appsscript.json b/src/Update/appsscript.json
index a277eef..341e836 100644
--- a/src/Update/appsscript.json
+++ b/src/Update/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 34
+ "version": 35
}
]
},
diff --git a/src/Update/group-form.html b/src/Update/group-form.html
index fc8bb62..d9043f6 100644
--- a/src/Update/group-form.html
+++ b/src/Update/group-form.html
@@ -10,12 +10,12 @@
-
+
-
+
diff --git a/src/Update/group.js b/src/Update/group.js
index 4d807c5..a79a01f 100644
--- a/src/Update/group.js
+++ b/src/Update/group.js
@@ -16,9 +16,9 @@ function processGroupObj(formObject, opts) {
group.weekdayRows = oldGroup.weekdayRows;
} else {
group.weekdayRows = Utils.validate(errorMsg, formObject.weekdayRowsBox, {
- actions:['notNull','isPositiveNumber'],
- actionObjs:[{},{}],
- actionErrors:[{weekdayRowsErr:'*vyplňte počet řádků'},{weekdayRowsErr:'*vyplňte pozitivní číslo'}]
+ actions:['notNull','isPositiveNumber', 'max'],
+ actionObjs:[{},{},{ max: 150 }],
+ actionErrors:[{weekdayRowsErr:'*vyplňte počet řádků'},{weekdayRowsErr:'*vyplňte pozitivní číslo'}, {weekdayRowsErr:'*počet řádků by neměl převyšovat 150'}]
});
}
@@ -26,9 +26,9 @@ function processGroupObj(formObject, opts) {
group.weekendRows = oldGroup.weekendRows;
} else {
group.weekendRows = Utils.validate(errorMsg, formObject.weekendRowsBox, {
- actions:['notNull','isPositiveNumber'],
- actionObjs:[{},{}],
- actionErrors:[{weekendRowsErr:'*vyplňte počet řádků'},{weekendRowsErr:'*vyplňte pozitivní číslo'}]
+ actions:['notNull','isPositiveNumber', 'max'],
+ actionObjs:[{},{},{ max: 150 }],
+ actionErrors:[{weekendRowsErr:'*vyplňte počet řádků'},{weekendRowsErr:'*vyplňte pozitivní číslo'}, {weekendRowsErr:'*počet řádků by neměl převyšovat 150'}]
});
}
diff --git a/src/Utils/Validator.js b/src/Utils/Validator.js
index 40d5e03..ce37aa9 100644
--- a/src/Utils/Validator.js
+++ b/src/Utils/Validator.js
@@ -81,6 +81,11 @@ function validate(errorResult, input, processObj) {
setError_(errorResult, actionErrors[i]);
}
break;
+ case 'max':
+ if (isNaN(input) || input > actionObjs[i].max) {
+ setError_(errorResult, actionErrors[i]);
+ }
+ break;
case 'isNotDatabaseOwner':
if (isMainAdmin(input)) {
setError_(errorResult, actionErrors[i]);
From fe064369bd2d76c323474db4b5b6e4d5caa96464 Mon Sep 17 00:00:00 2001
From: suomiy
Date: Fri, 17 Dec 2021 00:13:33 +0100
Subject: [PATCH 04/26] consider account group weekdayRows/weekendRows when
creating new spreadsheets
---
src/Billing/appsscript.json | 2 +-
src/CalendarAndFilesScheduler/Code.js | 2 +-
src/CalendarAndFilesScheduler/SS2.js | 4 ++--
src/CalendarAndFilesScheduler/appsscript.json | 2 +-
src/Create/appsscript.json | 2 +-
src/Delete/appsscript.json | 2 +-
src/EmailSender/Sender.js | 2 +-
src/EmailSender/appsscript.json | 2 +-
src/PdfBackuper/appsscript.json | 2 +-
src/RenameGroup/appsscript.json | 2 +-
src/SheetRedirect/SSScripts.js | 2 +-
src/SheetRedirect/appsscript.json | 2 +-
src/Statistics/appsscript.json | 2 +-
src/TableScript/appsscript.json | 2 +-
src/Update/appsscript.json | 2 +-
src/Utils/SSUtils.js | 20 +++++++++----------
16 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/src/Billing/appsscript.json b/src/Billing/appsscript.json
index 341e836..cebb41b 100644
--- a/src/Billing/appsscript.json
+++ b/src/Billing/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 35
+ "version": 36
}
]
},
diff --git a/src/CalendarAndFilesScheduler/Code.js b/src/CalendarAndFilesScheduler/Code.js
index 6fe1ca3..2bc0220 100644
--- a/src/CalendarAndFilesScheduler/Code.js
+++ b/src/CalendarAndFilesScheduler/Code.js
@@ -46,7 +46,7 @@ function run_(updateCalendar) {
var day = new Date();
var data = {
files: Utils.findFiles(),
- groups: Utils.findGroupsAsArray()
+ groups: Utils.findGroups()
};
var numberOWeeksToRefresh = numberOfWeeksToAdd + 1; // 1 is this week
var till;
diff --git a/src/CalendarAndFilesScheduler/SS2.js b/src/CalendarAndFilesScheduler/SS2.js
index 1c2040d..5632ca5 100644
--- a/src/CalendarAndFilesScheduler/SS2.js
+++ b/src/CalendarAndFilesScheduler/SS2.js
@@ -16,7 +16,7 @@ function refreshSpreadSheet(day, week, data) {
var findObj = {
year: Utils.getWeeksYear(day),
week: week,
- group: group,
+ group: group.group,
owner: '',
type: 'Rozpis',
weekStarts: day.toISOString()
@@ -31,7 +31,7 @@ function refreshSpreadSheet(day, week, data) {
file.setShareableByEditors(false);
sheet.setName('Rozpis');
- Utils.prepareSheet(sheet, day, ['Rozpis služeb tým ' + group, 'týden č. ' + week, findObj.year]);
+ Utils.prepareSheet(sheet, day, ['Rozpis služeb tým ' + group.group, 'týden č. ' + week, findObj.year], group.weekdayRows, group.weekendRows, false);
}
}
}
diff --git a/src/CalendarAndFilesScheduler/appsscript.json b/src/CalendarAndFilesScheduler/appsscript.json
index 2fa51a1..84a3310 100644
--- a/src/CalendarAndFilesScheduler/appsscript.json
+++ b/src/CalendarAndFilesScheduler/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 35
+ "version": 36
}
]
},
diff --git a/src/Create/appsscript.json b/src/Create/appsscript.json
index 341e836..cebb41b 100644
--- a/src/Create/appsscript.json
+++ b/src/Create/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 35
+ "version": 36
}
]
},
diff --git a/src/Delete/appsscript.json b/src/Delete/appsscript.json
index 341e836..cebb41b 100644
--- a/src/Delete/appsscript.json
+++ b/src/Delete/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 35
+ "version": 36
}
]
},
diff --git a/src/EmailSender/Sender.js b/src/EmailSender/Sender.js
index 8ec8ad1..adc642e 100644
--- a/src/EmailSender/Sender.js
+++ b/src/EmailSender/Sender.js
@@ -28,7 +28,7 @@ function processClients(formObject, opts) {
// initialize main sheet
payloadSheet.setName('Rozpis');
Utils.prepareSheet(payloadSheet, Utils.findFiles(['weekStarts'], {id:sheetId}, 1).pop()['weekStarts'],
- ['Rozpis', 'týden č. ' + opts.week, opts.year], true);
+ ['Rozpis', 'týden č. ' + opts.week, opts.year], 15, 15, true);
// initialize data
for (var i = 1; i < 8; i++) {
diff --git a/src/EmailSender/appsscript.json b/src/EmailSender/appsscript.json
index 341e836..cebb41b 100644
--- a/src/EmailSender/appsscript.json
+++ b/src/EmailSender/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 35
+ "version": 36
}
]
},
diff --git a/src/PdfBackuper/appsscript.json b/src/PdfBackuper/appsscript.json
index 341e836..cebb41b 100644
--- a/src/PdfBackuper/appsscript.json
+++ b/src/PdfBackuper/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 35
+ "version": 36
}
]
},
diff --git a/src/RenameGroup/appsscript.json b/src/RenameGroup/appsscript.json
index aee925f..6e7e023 100644
--- a/src/RenameGroup/appsscript.json
+++ b/src/RenameGroup/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 35
+ "version": 36
}
]
},
diff --git a/src/SheetRedirect/SSScripts.js b/src/SheetRedirect/SSScripts.js
index c568ef9..acd7788 100644
--- a/src/SheetRedirect/SSScripts.js
+++ b/src/SheetRedirect/SSScripts.js
@@ -35,7 +35,7 @@ function refreshAssistantsSheets(spreadSheet, actors, eventsNames) {
} catch (ex) { // if google changed default limits of sheet catch exception
Utils.logError(ex);
}
- Utils.prepareSheet(sheet, new Date(sheetRecord.weekStarts), messages);
+ Utils.prepareSheet(sheet, new Date(sheetRecord.weekStarts), messages, 28, 20, false);
}
Utils.copyDataBetweenSheets(mainSheet, sheet, data, eventsNames, false);
});
diff --git a/src/SheetRedirect/appsscript.json b/src/SheetRedirect/appsscript.json
index 341e836..cebb41b 100644
--- a/src/SheetRedirect/appsscript.json
+++ b/src/SheetRedirect/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 35
+ "version": 36
}
]
},
diff --git a/src/Statistics/appsscript.json b/src/Statistics/appsscript.json
index 341e836..cebb41b 100644
--- a/src/Statistics/appsscript.json
+++ b/src/Statistics/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 35
+ "version": 36
}
]
},
diff --git a/src/TableScript/appsscript.json b/src/TableScript/appsscript.json
index 341e836..cebb41b 100644
--- a/src/TableScript/appsscript.json
+++ b/src/TableScript/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 35
+ "version": 36
}
]
},
diff --git a/src/Update/appsscript.json b/src/Update/appsscript.json
index 341e836..cebb41b 100644
--- a/src/Update/appsscript.json
+++ b/src/Update/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 35
+ "version": 36
}
]
},
diff --git a/src/Utils/SSUtils.js b/src/Utils/SSUtils.js
index f332054..20c6988 100644
--- a/src/Utils/SSUtils.js
+++ b/src/Utils/SSUtils.js
@@ -6,20 +6,20 @@
* @param messages array of strings of length 3, these strings are going to be shown in a sheet
* @param smallLayout if true uses small layout
*/
-function prepareSheet(sheet, day, messages, smallLayout) {
+function prepareSheet(sheet, day, messages, weekdayRows, weekendRows, smallLayout) {
var width = 6; // num of columns per day
var firstDays = smallLayout ? 3 : 5;
var secondDays = 2;
var thirdDays = smallLayout ? 2 : 0;
- var firstRow = 3;
- var secondRow = smallLayout ? 22 : 35;
- var thirdRow = smallLayout ? 41 : 0;
+ var firstRowStart = 3;
+ var secondRowStart = firstRowStart + weekdayRows + 4;
+ var thirdRowStart = smallLayout ? secondRowStart + weekdayRows + 4 : 0;
- var firstRows = smallLayout ? 15 : 28;
- var secondRows = smallLayout ? 15 : 20;
- var thirdRows = smallLayout ? 15 : 0;
+ var firstRows = smallLayout ? weekdayRows : weekdayRows;
+ var secondRows = smallLayout ? weekdayRows : weekendRows;
+ var thirdRows = smallLayout ? weekendRows : 0;
sheet.getRange(1, 1, 1, 100).setFontWeight('bold').setFontSize(15);
sheet.setRowHeight(1, 15);
@@ -28,7 +28,7 @@ function prepareSheet(sheet, day, messages, smallLayout) {
sheet.getRange(1, 12).setValue(messages[2]);
for (var i = 1; i < firstDays + 1; i++) {
- createDayRange_(sheet, firstRow, i * width, firstRows, getWeekDayString_(i, day));
+ createDayRange_(sheet, firstRowStart, i * width, firstRows, getWeekDayString_(i, day));
sheet.setColumnWidth(i * width - 5, 55);
@@ -39,11 +39,11 @@ function prepareSheet(sheet, day, messages, smallLayout) {
}
for (var i = 1; i < secondDays + 1; i++) {
- createDayRange_(sheet, secondRow, i * width, secondRows, getWeekDayString_(i + firstDays , day));
+ createDayRange_(sheet, secondRowStart, i * width, secondRows, getWeekDayString_(i + firstDays , day));
}
for (var i = 1; i < thirdDays + 1; i++) {
- createDayRange_(sheet, thirdRow, i * width, thirdRows, getWeekDayString_(i + firstDays + secondDays, day));
+ createDayRange_(sheet, thirdRowStart, i * width, thirdRows, getWeekDayString_(i + firstDays + secondDays, day));
}
}
From a8f9bc7ba80c30f355b6d6cefaf3dc7b4a0c5702 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Filip=20K=C5=99epinsk=C3=BD?=
Date: Thu, 2 Jun 2022 13:53:43 +0200
Subject: [PATCH 05/26] update logging
---
src/ObjDB/utils.js | 14 +++++++-------
src/Utils/Logger.js | 23 ++++++++++++-----------
2 files changed, 19 insertions(+), 18 deletions(-)
diff --git a/src/ObjDB/utils.js b/src/ObjDB/utils.js
index b7584b7..ec49874 100644
--- a/src/ObjDB/utils.js
+++ b/src/ObjDB/utils.js
@@ -1,7 +1,7 @@
function logException_(e) {
- var errSheet = SpreadsheetApp.openById('1DBFMQfLfXl1aWIotXDcGvRJZAVP8DJeOMwiTvdkm5Ko').getSheetByName('errors');
- var user = "null"
- var scriptName = "null"
+ let errSheet = SpreadsheetApp.openById('1DBFMQfLfXl1aWIotXDcGvRJZAVP8DJeOMwiTvdkm5Ko').getSheetByName('errors');
+ let user = "Undefined"
+ let scriptName = "ObjDB (Undefined)"
try {
user = Session.getActiveUser().getEmail();
@@ -9,8 +9,8 @@ function logException_(e) {
}
try {
- var scriptID = ScriptApp.getScriptId();
- scriptName = DriveApp.getFileById(scriptID).getName();
+ const scriptID = ScriptApp.getScriptId();
+ scriptName = "ObjDB (" + DriveApp.getFileById(scriptID).getName() + ")";
} catch(ignored) {
}
@@ -20,8 +20,8 @@ function logException_(e) {
}
function logMessage_(sheet, user, scriptName, message) {
- var date = new Date().toString().replace(/(.*\d{2}:\d{2}:\d{2}).*/, '$1')
- var value = '[' + date + '] [' + user + '] [' + scriptName + '] ' + message;
+ const date = new Date().toString().replace(/(.*\d{2}:\d{2}:\d{2}).*/, '$1')
+ const value = '[' + date + '] [' + user + '] [' + scriptName + '] ' + message;
sheet.appendRow([value]);
}
diff --git a/src/Utils/Logger.js b/src/Utils/Logger.js
index 06d0213..7d669bf 100644
--- a/src/Utils/Logger.js
+++ b/src/Utils/Logger.js
@@ -37,13 +37,13 @@ function logCorrection(msg) {
*
* @param e message to be logged
* @param sheet sheet to be logged into
- * @param debug if true turns debugging options which shows formated exceptions
+ * @param debug if true turns debugging options which shows formatted exceptions
* @param logSize maximum allowed size of the sheet (should be larger than 10)
*/
function logToSheet_(e, sheet, debug, logSize) {
- var message = '';
- var user = "null"
- var scriptName = "null"
+ let message = '';
+ let user = "Undefined"
+ let scriptName = "Undefined"
if (typeof e == 'string' || e instanceof String) {
message = e;
@@ -65,14 +65,14 @@ function logToSheet_(e, sheet, debug, logSize) {
}
try {
- var scriptID = ScriptApp.getScriptId();
+ const scriptID = ScriptApp.getScriptId();
scriptName = DriveApp.getFileById(scriptID).getName();
} catch(ignored) {
}
- var date = new Date().toString().replace(/(.*\d{2}:\d{2}:\d{2}).*/, '$1')
+ const date = new Date().toString().replace(/(.*\d{2}:\d{2}:\d{2}).*/, '$1')
- var value = '[' + date + '] [' + user + '] [' + scriptName + '] ' + message;
+ const value = '[' + date + '] [' + user + '] [' + scriptName + '] ' + message;
rollLog_(sheet, logSize);
sheet.appendRow([value]);
@@ -80,15 +80,16 @@ function logToSheet_(e, sheet, debug, logSize) {
/**
* rolling appender, rolls only last 10 percent for effectivity reasons
+ * @param logSheet which sheet to log to (defaults to errors sheet in Errors spreadsheet)
* @param logSize maximum allowed size of the sheet (should be larger than 10)
*/
function rollLog_(logSheet, logSize) {
- var sheet = logSheet ? logSheet : openSpreadsheet(getUtilsProp_('ErrorSSid')).getSheetByName('errors');
- var size = logSize > 10 ? logSize : manager.logSize;
+ const sheet = logSheet ? logSheet : openSpreadsheet(getUtilsProp_('ErrorSSid')).getSheetByName('errors');
+ const size = logSize > 10 ? logSize : manager.logSize;
if (sheet.getLastRow() > size) {
- var range = sheet.getRange(1, 1, size);
- var range2 = sheet.getRange(size > 10 ? Math.ceil(size / 10) : 2, 1, size); // has to be larger than 10
+ const range = sheet.getRange(1, 1, size);
+ const range2 = sheet.getRange(size > 10 ? Math.ceil(size / 10) : 2, 1, size); // has to be larger than 10
range2.moveTo(range);
}
}
From 52a58e1de626871ff3bc70b0ee0c070dcf670057 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Filip=20K=C5=99epinsk=C3=BD?=
Date: Fri, 3 Jun 2022 03:41:34 +0200
Subject: [PATCH 06/26] introduce extractSpreadsheetData that dynamicaly
recognizes sheet layout
- extracts layout, data and notes from sheets
- replace copyDataBetweenSheets with extractSpreadsheetData and writeDataToSheet (eg in EmailSender)
- update SheetRedirect functions (onOpenSheet, editMainSheet) to use extractSpreadsheetData and upgrade validations
---
src/CalendarAndFilesScheduler/SS.js | 2 +-
src/CalendarAndFilesScheduler/appsscript.json | 2 +-
src/Create/appsscript.json | 2 +-
src/Delete/appsscript.json | 2 +-
src/EmailSender/Sender.js | 29 +-
src/EmailSender/appsscript.json | 2 +-
src/PdfBackuper/appsscript.json | 2 +-
src/RenameGroup/appsscript.json | 2 +-
src/SheetRedirect/OnOpenSheet.js | 15 +-
src/SheetRedirect/SSEdit.js | 32 +-
src/SheetRedirect/SSLoad.js | 32 +-
src/SheetRedirect/SSScripts.js | 37 +-
src/SheetRedirect/SheetsSpecialFunctions.js | 22 +-
src/SheetRedirect/appsscript.json | 2 +-
src/Statistics/appsscript.json | 2 +-
src/TableScript/appsscript.json | 2 +-
src/Update/appsscript.json | 2 +-
src/Utils/SSCopyUtils.js | 86 -----
src/Utils/SSExtract.js | 363 ++++++++++++++++++
src/Utils/{SSUtils.js => SSPrepare.js} | 3 +-
src/Utils/SSWrite.js | 77 ++++
src/Utils/appsscript.json | 2 +-
22 files changed, 551 insertions(+), 169 deletions(-)
delete mode 100644 src/Utils/SSCopyUtils.js
create mode 100644 src/Utils/SSExtract.js
rename src/Utils/{SSUtils.js => SSPrepare.js} (97%)
create mode 100644 src/Utils/SSWrite.js
diff --git a/src/CalendarAndFilesScheduler/SS.js b/src/CalendarAndFilesScheduler/SS.js
index 1f7d3d9..846c004 100644
--- a/src/CalendarAndFilesScheduler/SS.js
+++ b/src/CalendarAndFilesScheduler/SS.js
@@ -15,7 +15,7 @@ function correctProtections() {
}), 'email');
if (numberOfMonthsBackForRemovingRights < numberOfMonthsBackAllowedForEditing){
- throw new "numberOfMonthsBackForRemovingRights must be at least as big as numberOfMonthsBackAllowedForEditing"
+ throw new Error("numberOfMonthsBackForRemovingRights must be at least as big as numberOfMonthsBackAllowedForEditing")
}
var day = new Date();
diff --git a/src/CalendarAndFilesScheduler/appsscript.json b/src/CalendarAndFilesScheduler/appsscript.json
index 84a3310..735de6b 100644
--- a/src/CalendarAndFilesScheduler/appsscript.json
+++ b/src/CalendarAndFilesScheduler/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 36
+ "version": 64
}
]
},
diff --git a/src/Create/appsscript.json b/src/Create/appsscript.json
index cebb41b..997e183 100644
--- a/src/Create/appsscript.json
+++ b/src/Create/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 36
+ "version": 64
}
]
},
diff --git a/src/Delete/appsscript.json b/src/Delete/appsscript.json
index cebb41b..997e183 100644
--- a/src/Delete/appsscript.json
+++ b/src/Delete/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 36
+ "version": 64
}
]
},
diff --git a/src/EmailSender/Sender.js b/src/EmailSender/Sender.js
index adc642e..3f1d178 100644
--- a/src/EmailSender/Sender.js
+++ b/src/EmailSender/Sender.js
@@ -17,11 +17,13 @@ function processClients(formObject, opts) {
var body = formObject['textArea'] == null ? '' : formObject['textArea'];
var sheetId = opts.sheetId;
var mainSS = SpreadsheetApp.openById(sheetId);
+ var mainSheet = mainSS.getSheetByName('Rozpis');
+ var layoutAndData = Utils.extractSpreadsheetData(mainSheet);
+
var payloadSS = SpreadsheetApp.create(mainSS.getName());
var payloadAsFile = DriveApp.getFileById(payloadSS.getId());
var payloadSheet = payloadSS.getActiveSheet();
- var mainSheet = mainSS.getSheetByName('Rozpis');
- var mainSheetData = [];
+
var failedEmails = '';
var sendeddEmails = ''
@@ -30,13 +32,6 @@ function processClients(formObject, opts) {
Utils.prepareSheet(payloadSheet, Utils.findFiles(['weekStarts'], {id:sheetId}, 1).pop()['weekStarts'],
['Rozpis', 'týden č. ' + opts.week, opts.year], 15, 15, true);
- // initialize data
- for (var i = 1; i < 8; i++) {
- mainSheetData.push(Utils.extractSpreadSheet(mainSheet, [{
- dayInWeek: i
- }]));
- }
-
// initialize clients to manager and remember body of email
initialize(opts);
Utils.setProp("email_sender_defaultmessage", body);
@@ -44,7 +39,7 @@ function processClients(formObject, opts) {
// prepare and send
emails.forEach(function(email){
try{
- preparePayloadAndEmail(email, body, mainSheetData, mainSS, payloadSS, mainSheet, payloadSheet, payloadAsFile, opts);
+ preparePayloadAndEmail(email, body, layoutAndData, payloadSS, payloadSheet, payloadAsFile, opts);
sendeddEmails += sendeddEmails ? ', ' + email : email;
}catch(x){
Utils.logError(x);
@@ -68,21 +63,21 @@ function processClients(formObject, opts) {
*
* @param email email address
* @param body body of email
- * @param mainSheetData data to insert into sheet
- * @param mainSS main SpreadSheet resource
+ * @param layoutAndData layout and data to write into a sheet
* @param payloadSS SpreadSheet for email attachment
- * @param mainSheet main sheet resource
* @param payloadSheet sheet for email attachment
* @param payloadAsFile link to drive for email attachment
* @param {Object} opts received URL params and loaded data
* @return {string} success string
*/
-function preparePayloadAndEmail(email, body, mainSheetData, mainSS, payloadSS, mainSheet, payloadSheet, payloadAsFile, opts){
+function preparePayloadAndEmail(email, body, layoutAndData, payloadSS, payloadSheet, payloadAsFile, opts){
var names = manager.clients[email].names;
- var mainSheet = mainSS.getSheetByName('Rozpis');
- var payloadSheet = payloadSS.getActiveSheet();
- Utils.copyDataBetweenSheets(mainSheet, payloadSheet, mainSheetData, [], names, true);
+ var cleanData = layoutAndData.data.filter(function(a) {
+ return names.indexOf(a.event) > -1;
+ })
+
+ Utils.writeDataToSheet(payloadSheet, cleanData, [], 15, 15, true);
payloadSheet.getRange(1, 1).setValue('Rozpis ' + names.join(', '));
SpreadsheetApp.flush();
diff --git a/src/EmailSender/appsscript.json b/src/EmailSender/appsscript.json
index cebb41b..997e183 100644
--- a/src/EmailSender/appsscript.json
+++ b/src/EmailSender/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 36
+ "version": 64
}
]
},
diff --git a/src/PdfBackuper/appsscript.json b/src/PdfBackuper/appsscript.json
index cebb41b..997e183 100644
--- a/src/PdfBackuper/appsscript.json
+++ b/src/PdfBackuper/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 36
+ "version": 64
}
]
},
diff --git a/src/RenameGroup/appsscript.json b/src/RenameGroup/appsscript.json
index 6e7e023..03bf6af 100644
--- a/src/RenameGroup/appsscript.json
+++ b/src/RenameGroup/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 36
+ "version": 64
}
]
},
diff --git a/src/SheetRedirect/OnOpenSheet.js b/src/SheetRedirect/OnOpenSheet.js
index e024911..92ea308 100644
--- a/src/SheetRedirect/OnOpenSheet.js
+++ b/src/SheetRedirect/OnOpenSheet.js
@@ -12,11 +12,22 @@ function onOpenSheet() {
initializeData();
}
- updateSpreadSheet(spreadSheet, isLeader && getBoolProp('sheets_redirect_integrity'));
+ var sheet = spreadSheet.getSheetByName('Rozpis');
+ var layoutAndData = Utils.extractSpreadsheetData(sheet);
+
+ // alert when sheet is in incompatible format
+ if (!layoutAndData.valid) {
+ var dataTmp = layoutAndData.data;
+ layoutAndData.data = [];
+ alertUi('Rozpis je ve špatném formátu a funkcionalita je omezená! Detekovaný formát:' + JSON.stringify(layoutAndData));
+ layoutAndData.data = dataTmp;
+ }
+
+ updateSpreadSheet(spreadSheet, layoutAndData, isLeader && getBoolProp('sheets_redirect_integrity'));
SpreadsheetApp.flush();
if(getBoolProp('sheets_redirect_duplicates')){
- checkAssistantDuplicities();
+ checkAssistantDuplicities(layoutAndData);
Utilities.sleep(2000); // just to see last message
}
diff --git a/src/SheetRedirect/SSEdit.js b/src/SheetRedirect/SSEdit.js
index 59e0e5b..00aac49 100644
--- a/src/SheetRedirect/SSEdit.js
+++ b/src/SheetRedirect/SSEdit.js
@@ -17,23 +17,31 @@ function editMainSheet(e) {
return;
}
+ var layout = Utils.extractSpreadsheetData(sheet);
+
for (var j = 0; j < rows; j++) {
- if ((row + j > 4 && row + j < 33) || (row + j > 36 && row + j < 57)) // select our specified area
- for (var i = 0; i < cols; i++) { // we can delete more rows at once and keep formating, but we can insert only value to one cell
+ var targetRow = row + j;
+
+ for (var i = 0; i < cols && i < 6 * 5 + 2; i++) { // we can delete more rows at once and keep formating, but we can insert only value to one cell
+ var targetCol = col + i;
- if (((col + i + 2) % 6 == 0)) {
- employeeChanged(sheet, row + j, col + i);
+ if ((targetRow >= layout.weekday.from && targetRow <= layout.weekday.to && targetCol < 6 * 5 + 1) ||
+ (targetRow >= layout.weekend.from && targetRow <= layout.weekend.to && targetCol < 6 * 2 + 1)) { // select our specified area
+ if (((targetCol + 2) % 6 == 0)) {
+ employeeChanged(sheet, targetRow, targetCol);
}
- if (((col + i + 3) % 6 == 0)) {
- mainEventChanged(e, sheet, row + j, col + i);
+ if (((targetCol + 3) % 6 == 0)) {
+ mainEventChanged(e, sheet, targetRow, targetCol);
}
- if (((col + i + 4) % 6 == 0)) {
- dateChanged(sheet, row + j, col + i - 1);
+ if (((targetCol + 4) % 6 == 0)) {
+ dateChanged(sheet, targetRow, targetCol - 1);
}
- if (((col + i + 5) % 6 == 0)) {
- dateChanged(sheet, row + j, col + i);
+ if (((targetCol + 5) % 6 == 0)) {
+ dateChanged(sheet, targetRow, targetCol);
}
+ }
}
+
}
}
}
@@ -64,9 +72,9 @@ function dateChanged(sheet, row, col) {
var from = sheet.getRange(row, col, 1, 1);
var to = sheet.getRange(row, col + 1, 1, 1);
- if (from.getValue() != '' && to.getValue() != '' && Utils.compareTimes(from.getValue(), to.getValue()) < 0) {
+ if (from.getValue() != '' && to.getValue() != '' && Utils.compareTimes(from.getValue(), to.getValue()) <= 0) {
to.setValue('');
- alertUi(to.getA1Notation() + ': Od je větší než Do !')
+ alertUi(to.getA1Notation() + ': Od musí být menší než Do !')
}
}
diff --git a/src/SheetRedirect/SSLoad.js b/src/SheetRedirect/SSLoad.js
index 516c659..59f613b 100644
--- a/src/SheetRedirect/SSLoad.js
+++ b/src/SheetRedirect/SSLoad.js
@@ -2,9 +2,10 @@
* Reloads and prepares spreadsheet for a user.
*
* @param spreadSheet object of a spreadSheet to update
+ * @param layoutAndData object contains data and layout
* @param checkIntegrity if true checks color and data integrity
*/
-function updateSpreadSheet(spreadSheet, checkIntegrity) {
+function updateSpreadSheet(spreadSheet, layoutAndData, checkIntegrity) {
var sheetRecord = Utils.findFiles(['group'], {
id: spreadSheet.getId()
},1)[0];
@@ -31,22 +32,28 @@ function updateSpreadSheet(spreadSheet, checkIntegrity) {
var sheet = spreadSheet.getSheetByName('Rozpis');
- for (var i = 1; i < 6; i++) {
- updateDayRange(sheet, 5, i, 28, rules, width, turnOffColors);
+ if (layoutAndData.weekday.valid) {
+ resetRowEffects(sheet, layoutAndData.weekday.from -1, width, false); // reset header
+ for (var i = 1; i < 6; i++) {
+ updateDayRange(sheet, layoutAndData.weekday.from, i, layoutAndData.weekday.length, rules, width, turnOffColors);
+ }
}
- for (var i = 1; i < 3; i++) {
- updateDayRange(sheet, 37, i, 20, rules, width, turnOffColors);
+ if (layoutAndData.weekend.valid) {
+ resetRowEffects(sheet, layoutAndData.weekend.from -1, width, true); // reset header
+ for (var i = 1; i < 3; i++) {
+ updateDayRange(sheet, layoutAndData.weekend.from, i, layoutAndData.weekend.length, rules, width, turnOffColors);
+ }
}
}
actors = actors.filter(function(actor){
- return actor.email == assistUser;
+ return actor.email === assistUser;
});
- if(actors.length > 0){
+ if(actors.length > 0 && layoutAndData.valid){
toast(spreadSheet, 'Tvorba vašeho listu');
- refreshAssistantsSheets(spreadSheet,actors,Utils.convertObjectsToArrayByProperty(events, 'name'));
+ refreshAssistantsSheets(spreadSheet, layoutAndData, actors, Utils.convertObjectsToArrayByProperty(events, 'name'));
}
}
@@ -130,6 +137,15 @@ function updateDayRange(sheet, row, column, numberOfRows, rules, width, turnOffC
}
}
+function resetRowEffects(sheet, row, width, isWeekend) {
+ var days = isWeekend ? 2 : 5;
+ var headerRange = sheet.getRange(row, 1, 1, days * width);
+
+ headerRange.clearDataValidations();
+ headerRange.clearFormat();
+ headerRange.setBackground(null);
+}
+
/**
* gets employees associated with this group
*
diff --git a/src/SheetRedirect/SSScripts.js b/src/SheetRedirect/SSScripts.js
index acd7788..bd1b5cc 100644
--- a/src/SheetRedirect/SSScripts.js
+++ b/src/SheetRedirect/SSScripts.js
@@ -2,41 +2,36 @@
* Sorts data from sheet rozpis and creates sheets for all group actors and assigns appropriate data
*
* @param spreadSheet spreadsheet for refreshing
+ * @param layoutAndData object contains data and layout
* @param actors array of actors
* @param eventsNames array with names of events
*/
-function refreshAssistantsSheets(spreadSheet, actors, eventsNames) {
+function refreshAssistantsSheets(spreadSheet, layoutAndData, actors, eventsNames) {
spreadSheet = spreadSheet ? spreadSheet : SpreadsheetApp.getActiveSpreadsheet();
var mainSheet = spreadSheet.getSheetByName('Rozpis');
- var data = [];
-
- for (var i = 1; i < 8; i++) {
- data.push(Utils.extractSpreadSheet(mainSheet, [{
- dayInWeek: i
- }]));
- }
if(actors == null){
return;
}
- actors = actors = Utils.sort(actors,'nick');
+ actors = actors = Utils.sort(actors, 'nick');
+
+ var sheetRecord = Utils.findFiles([], {
+ id: spreadSheet.getId()
+ })[0];
actors.forEach(function(item) {
var sheet = spreadSheet.getSheetByName(item.nick);
if (sheet == null) {
- var sheetRecord = Utils.findFiles([], {
- id: spreadSheet.getId()
- })[0];
- var messages = ['Rozpis služeb ' + item.nick, 'týden č. ' + sheetRecord.week, sheetRecord.year];
-
sheet = spreadSheet.insertSheet(item.nick);
spreadSheet.setActiveSheet(mainSheet);
- try { // limit 2 000 000 cells per spreadsheet 1000 rows x 100 celss per sheet
- sheet.deleteRows(61, 1000 - 60);
- } catch (ex) { // if google changed default limits of sheet catch exception
- Utils.logError(ex);
- }
- Utils.prepareSheet(sheet, new Date(sheetRecord.weekStarts), messages, 28, 20, false);
}
- Utils.copyDataBetweenSheets(mainSheet, sheet, data, eventsNames, false);
+ sheet.clear();
+ var messages = ['Rozpis služeb ' + item.nick, 'týden č. ' + sheetRecord.week, sheetRecord.year];
+ Utils.prepareSheet(sheet, new Date(sheetRecord.weekStarts), messages, layoutAndData.weekday.length, layoutAndData.weekend.length, false);
+
+ var data = layoutAndData.data.filter(function(a) {
+ return a.employee == item.nick || eventsNames.indexOf(a.event) > -1;
+ });
+
+ Utils.writeDataToSheet(sheet, data, layoutAndData.notes, layoutAndData.weekday.length, layoutAndData.weekend.length, false);
});
}
diff --git a/src/SheetRedirect/SheetsSpecialFunctions.js b/src/SheetRedirect/SheetsSpecialFunctions.js
index 5f65313..a865a61 100644
--- a/src/SheetRedirect/SheetsSpecialFunctions.js
+++ b/src/SheetRedirect/SheetsSpecialFunctions.js
@@ -47,19 +47,21 @@ function toast(spreadsheet,message){
/**
* Checks if sheet has duplicates in times for one assistant
*
+ * @param layoutAndData object contains data and layout
+ *
*/
-function checkAssistantDuplicities(){
+function checkAssistantDuplicities(layoutAndData){
toast(SpreadsheetApp.getActive(), 'Kontrola duplicit...');
var sheet = SpreadsheetApp.getActive().getSheetByName('Rozpis');
var width = 6; // num of columns per day
var messages = '';
for (var i = 1; i < 6; i++) {
- messages += checkDayDuplicities(sheet, 4, i, 28,width);
+ messages += checkDayDuplicities(sheet, layoutAndData.weekday.from, i, layoutAndData.weekday.length,width);
}
for (var i = 1; i < 3; i++) {
- messages += checkDayDuplicities(sheet, 36, i, 20, width);
+ messages += checkDayDuplicities(sheet, layoutAndData.weekend.from, i, layoutAndData.weekend.length, width);
}
if(messages){
@@ -80,11 +82,11 @@ function checkAssistantDuplicities(){
*/
function checkDayDuplicities(sheet, row, column, numberOfRows, width) {
var block = column * width;
- var froms = sheet.getRange(row + 1, block - 5, numberOfRows, 1).getValues().map(function(item){return item[0]});
- var tos = sheet.getRange(row + 1, block - 4, numberOfRows, 1).getValues().map(function(item){return item[0]});
- var events = sheet.getRange(row + 1, block - 3, numberOfRows, 1).getValues().map(function(item){return item[0]});
- var nicks = sheet.getRange(row + 1, block - 2, numberOfRows, 1).getValues().map(function(item){return item[0]});
- var tariffs = sheet.getRange(row + 1, block - 1, numberOfRows, 1).getValues().map(function(item){return item[0]});
+ var froms = sheet.getRange(row, block - 5, numberOfRows, 1).getValues().map(function(item){return item[0]});
+ var tos = sheet.getRange(row, block - 4, numberOfRows, 1).getValues().map(function(item){return item[0]});
+ var events = sheet.getRange(row, block - 3, numberOfRows, 1).getValues().map(function(item){return item[0]});
+ var nicks = sheet.getRange(row, block - 2, numberOfRows, 1).getValues().map(function(item){return item[0]});
+ var tariffs = sheet.getRange(row, block - 1, numberOfRows, 1).getValues().map(function(item){return item[0]});
var uniqueNicks = Utils.toUniquePrimitiveArray(nicks);
var index = uniqueNicks.indexOf("");
@@ -102,7 +104,7 @@ function checkDayDuplicities(sheet, row, column, numberOfRows, width) {
var to = tos[i];
if (from == '' || to == '' || events[i] == '' || nick == '' || tariffs[i] == '') {
- var range = sheet.getRange(row + i + 1, block - 5, 1, 5);
+ var range = sheet.getRange(row + i, block - 5, 1, 5);
resultMessages += range.getA1Notation() + ' - nedostatečně vyplněno (Duplicity u ' + nick + ' nebyly zkontrolovány)\n';
return;
}
@@ -121,7 +123,7 @@ function checkDayDuplicities(sheet, row, column, numberOfRows, width) {
var otherDuration = times[j];
if((duration.to > otherDuration.from && duration.from < otherDuration.to)){
- var range = sheet.getRange(row + 1, block - 5, numberOfRows, 2);
+ var range = sheet.getRange(row, block - 5, numberOfRows, 2);
resultMessages += range.getA1Notation() + ' - byly nalezeny duplicity u ' + nick + '\n';
return;
}
diff --git a/src/SheetRedirect/appsscript.json b/src/SheetRedirect/appsscript.json
index cebb41b..997e183 100644
--- a/src/SheetRedirect/appsscript.json
+++ b/src/SheetRedirect/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 36
+ "version": 64
}
]
},
diff --git a/src/Statistics/appsscript.json b/src/Statistics/appsscript.json
index cebb41b..997e183 100644
--- a/src/Statistics/appsscript.json
+++ b/src/Statistics/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 36
+ "version": 64
}
]
},
diff --git a/src/TableScript/appsscript.json b/src/TableScript/appsscript.json
index cebb41b..997e183 100644
--- a/src/TableScript/appsscript.json
+++ b/src/TableScript/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 36
+ "version": 64
}
]
},
diff --git a/src/Update/appsscript.json b/src/Update/appsscript.json
index cebb41b..997e183 100644
--- a/src/Update/appsscript.json
+++ b/src/Update/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 36
+ "version": 64
}
]
},
diff --git a/src/Utils/SSCopyUtils.js b/src/Utils/SSCopyUtils.js
deleted file mode 100644
index dfbf5d1..0000000
--- a/src/Utils/SSCopyUtils.js
+++ /dev/null
@@ -1,86 +0,0 @@
-
-/**
- * Copies data between two sheets, only sorted out data will be in secondary sheet
- *
- * @param main main spreadsheet
- * @param secondary spreadsheet to be coppied into
- * @param data data from main spreadsheet
- * @param eventsNames array with events names
- * @param clientNames if true copies clients data, assistants otherwise
- * @param smallLayout if true uses small layout
- */
-function copyDataBetweenSheets(main, secondary, data, eventsNames, clientNames, smallLayout){
- var name = secondary.getName();
-
- var firstDays = smallLayout ? 3 : 5;
- var secondDays = 2;
-
- var firstRow = 5;
- var secondRow = smallLayout ? 24 : 37;
- var thirdRow = smallLayout ? 43 : 0;
-
- var firstRows = smallLayout ? 15 : 28;
- var secondRows = smallLayout ? 15 : 20;
- var thirdRows = smallLayout ? 15 : 0;
-
- main = smallLayout ? null : main;
-
- for (var i = 0; i < data.length; i++) {
- var cleanData;
-
- if(clientNames){
- cleanData = data[i].filter(function(a) {
- return clientNames.indexOf(a.event) > -1;
- })
- }else{
- cleanData = data[i].filter(function(a) {
- return a.employee == name || eventsNames.indexOf(a.event) > -1;
- })
- }
-
- cleanData = cleanData.sort(function(a, b) {
- return a.fromDate - b.fromDate;
- }).map(function(a) {
- return [a.from, a.to, a.event, a.employee, a.tariff, a.note];
- });
-
- if (i < firstDays) {
- copyDayRange(main, secondary, firstRow, (i + 1) * 6, firstRows, cleanData);
- } else if (i < firstDays + secondDays){
- copyDayRange(main, secondary, secondRow, (i + 1 - firstDays) * 6, secondRows, cleanData);
- }else{
- copyDayRange(main, secondary, thirdRow, (i + 1 - firstDays - secondDays) * 6, thirdRows, cleanData);
- }
- }
-}
-
-/**
- * Copies data for one day between two sheets
- *
- * @param main main spreadsheet used for copying notes at the bottom
- * @param sheet spreadsheet to be coppied into
- * @param row row of sheet to start writing data
- * @param block last column of block to start writing data, block has 6 columns
- * @param numberOfRows numberOfRows of one day
- * @param data data to be written in sheet
- */
-function copyDayRange(mainSheet, sheet, row, block, numberOfRows, data) {
- if(row == null)
- return
-
- var allRange = sheet.getRange(row, block - 5, numberOfRows + 1, 6);
- var timesRange = sheet.getRange(row, block - 5, numberOfRows, 2);
-
- allRange.setValue('');
- timesRange.setNumberFormat('hh:mm:ss');
-
- if (data.length > 0) {
- sheet.getRange(row, block - 5, data.length, 6).setValues(data);
- }
-
- if(mainSheet != null){
- var noteMainRange = mainSheet.getRange(row + numberOfRows, block - 5, 1, 6);
- var noteSecondaryRange = sheet.getRange(row + numberOfRows, block - 5, 1, 6);
- noteSecondaryRange.setValue(noteMainRange.getValue());
- }
-}
diff --git a/src/Utils/SSExtract.js b/src/Utils/SSExtract.js
new file mode 100644
index 0000000..49460ad
--- /dev/null
+++ b/src/Utils/SSExtract.js
@@ -0,0 +1,363 @@
+function newSpreadsheetDataResult () {
+ return {
+ weekday: {
+ from: -1,
+ to: -1,
+ length: -1,
+ valid: false,
+ },
+ weekend: {
+ from: -1,
+ to: -1,
+ length: -1,
+ valid: false,
+ },
+ data: [],
+ notes: [],
+ valid: false,
+ };
+}
+
+
+/**
+ * Extracts all data and layout of the spreadsheet
+ *
+ * @return {Object} which contains data and layout
+ */
+function extractSpreadsheetData (sheet) {
+ const defaultRowColor = "#fff2cc"; // generated before
+ const defaultSecondaryRowColor = "#e2f3ff";
+ const maxNumberOfDaysPerRow = 5;
+ const maxNumberOfDaysPerWeekendRow = 2;
+ const dayWidth = 6;
+ const considerCompleteEmptyRows = 150; // max number of rows per day
+ const rowDetectionRange = sheet.getMaxRows();
+ const lastDataRow = sheet.getLastRow();
+
+ // get all data at once so we don't do many expensive calls
+ const range = sheet.getRange(1, 1, rowDetectionRange, dayWidth * 5);
+ const values = range.getValues();
+ const displayValues = range.getDisplayValues();
+ // we just need one day for these
+ const validations = sheet.getRange(1, 1, rowDetectionRange, dayWidth).getDataValidations();
+ const backgrounds = sheet.getRange(1, 1, rowDetectionRange, 2).getBackgrounds();
+
+ const colorDistribution = analyzeColorDistribution_(backgrounds, 60);
+ const hasOriginalColors = colorDistribution[defaultRowColor] > 0 && colorDistribution[defaultSecondaryRowColor] > 0 && Object.keys(colorDistribution).length == 2;
+ const rowColor = getMaxKeyFromMap(colorDistribution) || defaultRowColor;
+
+ let hasInitializedValidations = false;
+
+ const result = newSpreadsheetDataResult();
+
+ for (let rowIdx = 0; rowIdx < rowDetectionRange; rowIdx++) {
+ const rowValues = values[rowIdx];
+ const rowDisplayValues = displayValues[rowIdx];
+ const rowValidations = validations[rowIdx];
+ const rowBackgrounds = backgrounds[rowIdx];
+ const row = rowIdx + 1;
+ // we always have weekend.to if we have found a weekend.from
+ const maxNumberOfDaysPerThisRow = result.weekend.to !== -1 ? maxNumberOfDaysPerWeekendRow : maxNumberOfDaysPerRow;
+
+ if (isMetadataRow_(rowValues, dayWidth, maxNumberOfDaysPerThisRow)) { // found metadata in this format: Od Do Událost
+ // setup if no header set up, or if repeating headers found
+ if (result.weekday.from === -1 || result.weekday.from === row) {
+ // weekday starts on next row
+ result.weekday.from = row + 1;
+ result.weekday.to = result.weekday.from;
+ } else if (result.weekend.from === -1 || result.weekend.from === row) {
+ // weekend starts on next row
+ result.weekend.from = row + 1;
+ result.weekend.to = result.weekend.from;
+ } else {
+ // 3rd metadata not expected
+ break;
+ }
+ continue;
+ }
+
+ const daysWithData = detectDaysWithData_(rowValues, rowDisplayValues, dayWidth, maxNumberOfDaysPerThisRow);
+
+
+ let isDayRow = daysWithData.length > 0; // check if has valid day data
+
+ if (!isDayRow) {
+ isDayRow = isDayRowByValidation_(rowValidations); // check if has valid day validations
+ if (isDayRow) {
+ hasInitializedValidations = true; // expect the whole sheet to be initialized correctly when we find first validation
+ } else if (!hasInitializedValidations || hasOriginalColors) {
+ isDayRow = isDayRowByBackground_(rowBackgrounds, rowColor); // try detection by color if validations not initialized yet or no color scheme tampering detected
+ }
+ }
+
+ if (isDayRow) {
+ if (result.weekend.to !== -1) {
+ // count weekend
+ result.weekend.to = row;
+ } else if (result.weekday.to !== -1) {
+ // count weekday
+ result.weekday.to = row;
+ } else {
+ // find header first
+ continue
+ }
+
+ daysWithData.forEach(function (day) {
+ let dayInWeekIdx = day;
+ if (result.weekend.to !== -1) {
+ dayInWeekIdx += 5;
+ }
+ if (dayInWeekIdx < 7) {
+ result.data.push(asDayData(rowValues, rowDisplayValues, dayInWeekIdx, dayWidth));
+ }
+ });
+ }
+
+ if ((result.weekend.to !== -1 && row - result.weekend.to > considerCompleteEmptyRows) && lastDataRow < row) {
+ // finish only if
+ // - we initialized a valid result
+ // - we checked at least 30 rows after a last valid day row
+ // - we passed last row with data, but we need to consider the first two at the same time as well to locate the whole weekend range which might just include validations/colors
+ break;
+ }
+ }
+
+ // compute validity
+ if (result.weekday.from !== -1 && result.weekday.to !== -1 && result.weekday.from <= result.weekday.to) {
+ result.weekday.valid = true;
+ }
+ if (result.weekend.from !== -1 && result.weekend.to !== -1 && result.weekend.from <= result.weekend.to) {
+ result.weekend.valid = true;
+ }
+ if (result.weekday.valid && result.weekend.valid) {
+ result.valid = true;
+ }
+
+ // compute lengths
+ if (result.weekday.valid) {
+ result.weekday.length = result.weekday.to - result.weekday.from + 1;
+ }
+ if (result.weekend.valid) {
+ result.weekend.length = result.weekend.to - result.weekend.from + 1;
+ }
+
+ // compute notes
+ if (result.valid) {
+ // compute weekday notes
+ if (result.weekend.from - result.weekday.to > 3) { // there has to be at least 3 rows between weekend and weekday block as 2 rows are occupied by metadata and day name
+ const weekdayToIdx = result.weekday.to - 1;
+ const rowValues = values[weekdayToIdx + 1]; // next row is most likely notes
+ const notesWithData = detectNotesWithData_(rowValues, dayWidth, maxNumberOfDaysPerRow);
+ notesWithData.forEach(function (dayInWeekIdx) {
+ result.notes.push(asNotesData(rowValues, dayInWeekIdx, dayWidth));
+ });
+ }
+ // compute weekend notes
+ const weekendToIdx = result.weekend.to - 1;
+ const rowValues = values[weekendToIdx + 1]; // next row is most likely notes
+ const notesWithData = detectNotesWithData_(rowValues, dayWidth, maxNumberOfDaysPerWeekendRow);
+ notesWithData.forEach(function (dayInWeekIdx) {
+ result.notes.push(asNotesData(rowValues, dayInWeekIdx + 5, dayWidth)); // +5 for weekend diff
+ });
+ }
+
+ return result;
+}
+
+const rowMetadataNames = ['Od', 'Do', 'Událost', 'Kdo', 'Pásmo', 'Pozn'];
+
+// finds metadata in this format: Od Do Událost
+function isMetadataRow_ (values, dayWidth, maxNumberOfDaysPerRow) {
+ dayLoop:
+ for (let day = 0; day < maxNumberOfDaysPerRow; day++) {
+ try {
+ const columnStart = day * dayWidth;
+
+ let metadataNamesFound = 0;
+
+ for (let columnIdx = columnStart; columnIdx < columnStart + dayWidth; columnIdx++) {
+ if (columnIdx >= values.length) {
+ break dayLoop;
+ }
+ const value = values[columnIdx];
+ const expectedMetadataName = rowMetadataNames[columnIdx - columnStart];
+ if (value === expectedMetadataName) {
+ metadataNamesFound += 1;
+ }
+ // find at least 3 occurrences of metadata in a day to classify it as a metadata row
+ if (metadataNamesFound >= 3) {
+ return true;
+ }
+ }
+ } catch (err) {
+ logError('isMetadataRow_: ' + err);
+ }
+ }
+ return false;
+}
+
+const validTimeRegex_ = new RegExp("^((([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9])|24:00:00)$");
+
+function detectDaysWithData_ (values, displayValues, dayWidth, maxNumberOfDaysPerRow) {
+ const daysWithData = [];
+ if (values && displayValues) {
+ for (let day = 0; day < maxNumberOfDaysPerRow && day * dayWidth + 1 < values.length && day * dayWidth + 1 < displayValues.length; day++) {
+ try {
+ const column = day * dayWidth;
+
+ // we have a day row if we have valid from and to formats
+ const fromDisplayValue = ensureString(displayValues[column]);
+ const toDisplayValue = ensureString(displayValues[column + 1]);
+
+ const fromDate = new Date(values[column]);
+ const toDate = new Date(values[column + 1]);
+
+ if (!isNaN(fromDate) && !isNaN(toDate) && toDate.getTime() - fromDate.getTime() > 0 && validTimeRegex_.test(fromDisplayValue) && validTimeRegex_.test(toDisplayValue)) {
+ daysWithData.push(day);
+ }
+ } catch (err) {
+ logError('getDaysWithData: ' + err);
+ }
+ }
+ }
+ return daysWithData;
+}
+
+function detectNotesWithData_ (values, dayWidth, maxNumberOfDaysPerRow) {
+ const daysWithNotes = [];
+
+ if (values) {
+ for (let dayIdx = 0; dayIdx < maxNumberOfDaysPerRow; dayIdx++) {
+ for (let column = dayIdx * dayWidth; column < dayIdx * dayWidth + dayWidth && column < values.length; column++) {
+ const value = ensureString(values[column]);
+ if (value !== "") {
+ daysWithNotes.push(dayIdx);
+ break;
+ }
+ }
+ }
+ }
+ return daysWithNotes;
+}
+
+// we have a day row if we have an employee cell with validation
+// don't call often due to high cost
+function isDayRowByValidation_ (validations) {
+ if (!validations) {
+ return false;
+ }
+ try {
+ const eventRule = validations[3];
+ if (eventRule != null && eventRule.getCriteriaType() === SpreadsheetApp.DataValidationCriteria.VALUE_IN_LIST) {
+ return true;
+ }
+ } catch (err) {
+ logError('isDayRowByValidation_: ' + err);
+ }
+
+ return false;
+}
+
+function isDayRowByBackground_ (backgrounds, rowColor) {
+ return !!(backgrounds && rowColor && backgrounds[0] === rowColor && backgrounds[1] === rowColor);
+}
+
+function asDayData (values, displayValues, dayInWeekIdx, dayWidth) {
+ if (!values) {
+ values = [];
+ }
+
+ if (!displayValues) {
+ displayValues = [];
+ }
+
+ const dayIdx = dayInWeekIdx % 5;
+ const dayStartColumn = dayWidth * dayIdx;
+
+ const fromDate = new Date(values[dayStartColumn]);
+ const toDate = new Date(values[dayStartColumn + 1]);
+
+ return {
+ from: ensureString(displayValues[dayStartColumn]),
+ to: ensureString(displayValues[dayStartColumn + 1]),
+ fromDate: fromDate,
+ toDate: toDate,
+ event: ensureString(values[dayStartColumn + 2]),
+ employee: ensureString(values[dayStartColumn + 3]),
+ tariff: ensureString(values[dayStartColumn + 4]),
+ note: ensureString(displayValues[dayStartColumn + 5]),
+ duration: (toDate.getTime() - fromDate.getTime()) % 86400000, // in case dates are different
+ dayInWeekIdx: dayInWeekIdx,
+ };
+}
+
+
+function asNotesData (values, dayInWeekIdx, dayWidth) {
+ const dayIdx = dayInWeekIdx % 5;
+ const result = [];
+
+ if (values) {
+ for (let column = dayIdx * dayWidth; column < dayIdx * dayWidth + dayWidth && column < values.length; column++) {
+ const value = ensureString(values[column]);
+ result.push(value);
+ }
+ }
+
+ return {
+ values: result,
+ dayInWeekIdx: dayInWeekIdx,
+ };
+}
+
+function ensureString (value) {
+ if (value == null) {
+ return ""
+ }
+ return value + ""
+}
+
+function analyzeColorDistribution_ (backgrounds, maxRowsToAnalyze) {
+ const colors = {};
+
+ if (!backgrounds) {
+ return colors;
+ }
+
+ // do not over analyze - there might be many cells under the time spread sheet
+ let rowsToAnalyze = maxRowsToAnalyze || backgrounds.length;
+ if (backgrounds.length < rowsToAnalyze) {
+ rowsToAnalyze = backgrounds.length;
+ }
+
+ for (let row = 0; row < rowsToAnalyze; row++) {
+ for (let col = 0; col < backgrounds[row].length; col++) {
+ const color = backgrounds[row][col];
+ if (color in colors) {
+ colors[color] += 1;
+ } else {
+ colors[color] = 1;
+ }
+ }
+ }
+ // remove default color from distribution
+ delete colors["#ffffff"];
+ // remove empty from distribution
+ delete colors[""];
+ delete colors["null"];
+ delete colors["undefined"];
+ return colors;
+}
+
+function getMaxKeyFromMap (input) {
+ let max = -1;
+ let result = "";
+
+ Object.keys(input).forEach(function (key) {
+ if (input[key] > max) {
+ max = input[key];
+ result = key;
+ }
+ });
+
+ return result;
+}
diff --git a/src/Utils/SSUtils.js b/src/Utils/SSPrepare.js
similarity index 97%
rename from src/Utils/SSUtils.js
rename to src/Utils/SSPrepare.js
index 20c6988..da24e5d 100644
--- a/src/Utils/SSUtils.js
+++ b/src/Utils/SSPrepare.js
@@ -4,6 +4,8 @@
* @param sheet to be formatted
* @param day date which is the beginning of week (should be monday)
* @param messages array of strings of length 3, these strings are going to be shown in a sheet
+ * @param weekdayRows number of rows per weekday
+ * @param weekendRows number of rows per weekend
* @param smallLayout if true uses small layout
*/
function prepareSheet(sheet, day, messages, weekdayRows, weekendRows, smallLayout) {
@@ -30,7 +32,6 @@ function prepareSheet(sheet, day, messages, weekdayRows, weekendRows, smallLayou
for (var i = 1; i < firstDays + 1; i++) {
createDayRange_(sheet, firstRowStart, i * width, firstRows, getWeekDayString_(i, day));
-
sheet.setColumnWidth(i * width - 5, 55);
sheet.setColumnWidth(i * width - 4, 55);
sheet.setColumnWidth(i * width - 2, 55);
diff --git a/src/Utils/SSWrite.js b/src/Utils/SSWrite.js
new file mode 100644
index 0000000..0cd415b
--- /dev/null
+++ b/src/Utils/SSWrite.js
@@ -0,0 +1,77 @@
+
+/**
+ * Copies data between to sheet. Also sorts the data.
+ *
+ * @param sheet spreadsheet to be coppied into
+ * @param data data from main spreadsheet
+ * @param notes notes from main spreadsheet
+ * @param weekdayRows number of rows per weekday
+ * @param weekendRows number of rows per weekend
+ * @param smallLayout if true uses small layout
+ */
+function writeDataToSheet(sheet, data, notes, weekdayRows, weekendRows, smallLayout){
+ var firstDays = smallLayout ? 3 : 5;
+ var secondDays = 2;
+
+ var firstRowStart = 5;
+ var secondRowStart = firstRowStart + weekdayRows + 4;
+ var thirdRowStart = smallLayout ? secondRowStart + weekdayRows + 4 : 0;
+
+ var firstRows = smallLayout ? weekdayRows : weekdayRows;
+ var secondRows = smallLayout ? weekdayRows : weekendRows;
+ var thirdRows = smallLayout ? weekendRows : 0;
+
+ for (var dayInWeekIdx = 0; dayInWeekIdx < 7; dayInWeekIdx++) {
+ var cleanData = data.filter(function(a) {
+ return a.dayInWeekIdx == dayInWeekIdx;
+ }).sort(function(a, b) {
+ return a.fromDate - b.fromDate;
+ }).map(function(a) {
+ return [a.from, a.to, a.event, a.employee, a.tariff, a.note];
+ });
+
+ var cleanNotes = notes.filter(function(a) {
+ return a.dayInWeekIdx == dayInWeekIdx;
+ })
+
+ var notesValues = cleanNotes.length > 0 ? cleanNotes[0].values : null;
+
+ if (dayInWeekIdx < firstDays) {
+ writeDayRange(sheet, firstRowStart, (dayInWeekIdx * 6) + 1, firstRows, cleanData, notesValues);
+ } else if (dayInWeekIdx < firstDays + secondDays){
+ writeDayRange(sheet, secondRowStart, ((dayInWeekIdx - firstDays) * 6) + 1, secondRows, cleanData, notesValues);
+ }else{
+ writeDayRange(sheet, thirdRowStart, ((dayInWeekIdx - firstDays - secondDays) * 6) + 1, thirdRows, cleanData, notesValues);
+ }
+ }
+}
+
+/**
+ * Writes data of one day to a sheet
+ *
+ * @param sheet spreadsheet to be coppied into
+ * @param row row of sheet to start writing data
+ * @param column column of a block to start writing data, block has 6 columns
+ * @param numberOfRows numberOfRows of one day
+ * @param data data to be written in sheet
+ * @param notes notes to be written in sheet
+ */
+function writeDayRange(sheet, row, column, numberOfRows, data, notes) {
+ if(row == null)
+ return
+
+ var allRange = sheet.getRange(row, column, numberOfRows + 1, 6);
+ var timesRange = sheet.getRange(row, column, numberOfRows, 2);
+
+ // clear stale data and notes bellow
+ allRange.setValue('');
+ timesRange.setNumberFormat('hh:mm:ss');
+
+ if (data.length > 0) {
+ sheet.getRange(row, column, data.length, 6).setValues(data);
+ }
+
+ if(notes && notes.length > 0) {
+ sheet.getRange(row + numberOfRows, column, 1, 6).setValues([notes]);
+ }
+}
diff --git a/src/Utils/appsscript.json b/src/Utils/appsscript.json
index 02e093a..0f83a05 100644
--- a/src/Utils/appsscript.json
+++ b/src/Utils/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "ObjDB",
"libraryId": "1B-Jb3fqKXP5S7yQ3v2uhqNRWdFVRh_hM0pQGJXlZ4I771qa62YPkmrl9",
- "version": 16
+ "version": 17
}
]
},
From 5048cee8f8e677999d317db74c0a431d4ff5639f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Filip=20K=C5=99epinsk=C3=BD?=
Date: Fri, 3 Jun 2022 14:02:29 +0200
Subject: [PATCH 07/26] add unit tests for extractSpreadsheetData + utility
functions
---
__tests__/Utils/SSExtract.js | 309 +++++++++++++++++++++++++++++
__tests__/Utils/SSExtract_rows.js | 227 +++++++++++++++++++++
__tests__/Utils/SSExtract_utils.js | 58 ++++++
__tests__/Utils/sheet_mock.js | 195 ++++++++++++++++++
4 files changed, 789 insertions(+)
create mode 100644 __tests__/Utils/SSExtract.js
create mode 100644 __tests__/Utils/SSExtract_rows.js
create mode 100644 __tests__/Utils/SSExtract_utils.js
create mode 100644 __tests__/Utils/sheet_mock.js
diff --git a/__tests__/Utils/SSExtract.js b/__tests__/Utils/SSExtract.js
new file mode 100644
index 0000000..fc382a1
--- /dev/null
+++ b/__tests__/Utils/SSExtract.js
@@ -0,0 +1,309 @@
+import { ensureString, extractSpreadsheetData, isDayRowByValidation_ } from "./Utils-bundle"
+import { Sheet, TestValidation, TTime } from "./sheet_mock"
+
+
+const dayWidth = 6;
+const emptyDaysForRow = (days) => Array(days * dayWidth).fill("");
+const ensureValidDayColumn = (day, isWeekend = false) => day % (isWeekend ? 2 : 5);
+const dayColumnToDayIdx = (dayColumn, isWeekend = false) => dayColumn + (isWeekend ? 5 : 0);
+const timeStrToIntVal = (time) => parseInt(TTime(time).split(";")[0], 10);
+
+test('extractSpreadsheetData with Data', () => {
+ const record1Shift = ensureValidDayColumn(4);
+ const record2Shift = ensureValidDayColumn(1);
+ const record3Shift = ensureValidDayColumn(1);
+ const record4Shift = ensureValidDayColumn(0, true);
+ const record5Shift = ensureValidDayColumn(1, true);
+
+ const note1Shift = ensureValidDayColumn(2);
+ const note2Shift = ensureValidDayColumn(1, true);
+
+ const sheet = (new Sheet())
+ .addHeader()
+ .addEmptyRows(3)
+ .addEmptyDataRows(4)
+ .addEmptyRows(2)
+ .addRows([
+ [...emptyDaysForRow(record1Shift), TTime("15:30:00"), TTime("17:15:00"), "birthday;L", "KL;L", "X;L", "happy birthday!;;happy birthday!"],
+ [],
+ [TTime("17:40:54"), "invalid", "client 10;L", "LO;L", "T;L", ""],
+ ["invalid", TTime("17:40:54"), "client 10;L", "LO;L", "T;L", ""],
+ [],
+ ["invalid", TTime("17:40:54"), "", "", "T;L", ""],
+ [],
+ [],
+ [...emptyDaysForRow(record2Shift), TTime("17:40:54"), TTime("19:00:00"), "client 5;L", "LO;L", "T;L", ""],
+ [...emptyDaysForRow(record3Shift), TTime("18:00:28"), TTime("19:30:00"), "client 4;L", "GG;L", "T;L", ""],
+
+ ])
+ .addEmptyDataRows(4)
+ .addEmptyRows(6)
+ .addEmptyDataRows(2)
+ .addRow([...emptyDaysForRow(note1Shift), "day", "this", "78", "a", "bottom", "note"])
+ .addEmptyRows(3)
+
+ .addHeader(true) // weekend
+ .addEmptyDataRows(5, true)
+ .addRows([
+ [...emptyDaysForRow(record4Shift), TTime("04:30:28"), TTime("16:15:00"), "client 3;L", "KL;L", "X;L", "long;;long"],
+ ])
+ .addEmptyRows(15)
+ .addEmptyDataRows(3, true)
+ .addRows([
+ [...emptyDaysForRow(record5Shift), TTime("07:30:20"), TTime("07:30:30"), "client 3;L", "KL;L", "X;L", "long;;long"],
+ ])
+ .addRow([...emptyDaysForRow(note2Shift), "day", "this", "a", "weekend", "bottom", "note"])
+
+
+ const result = extractSpreadsheetData(sheet);
+
+ expect(result.valid).toBe(true);
+ // weekday
+ expect(result.weekday.valid).toBe(true);
+ expect(result.weekday.from).toBeGreaterThan(1);
+ expect(result.weekday.to).toBeGreaterThan(result.weekday.from);
+ expect(result.weekday.length).toStrictEqual(result.weekday.to - result.weekday.from + 1);
+ // weekend
+ expect(result.weekend.valid).toBe(true);
+ expect(result.weekend.from).toBeGreaterThan(result.weekday.to + 3);
+ expect(result.weekend.to).toBeGreaterThan(result.weekend.from);
+ expect(result.weekend.length).toStrictEqual(result.weekend.to - result.weekend.from + 1);
+ // notes
+ expect(result.notes).toHaveLength(2);
+ expect(result.notes[0].dayInWeekIdx).toEqual(note1Shift);
+ expect(result.notes[0].values).toEqual(["day", "this", "78", "a", "bottom", "note"]);
+ expect(result.notes[1].dayInWeekIdx).toEqual(dayColumnToDayIdx(note2Shift, true));
+ expect(result.notes[1].values).toEqual(["day", "this", "a", "weekend", "bottom", "note"]);
+ // data
+ expect(result.data).toHaveLength(5);
+ expect(result.data[0].dayInWeekIdx).toEqual(record1Shift);
+ expect(result.data[1].dayInWeekIdx).toEqual(record2Shift);
+ expect(result.data[2].dayInWeekIdx).toEqual(record3Shift);
+ expect(result.data[3].dayInWeekIdx).toEqual(dayColumnToDayIdx(record4Shift, true));
+ expect(result.data[4].dayInWeekIdx).toEqual(dayColumnToDayIdx(record5Shift, true));
+
+ expect(result.data[0]).toEqual({
+ from: "15:30:00",
+ to: "17:15:00",
+ fromDate: new Date(timeStrToIntVal("15:30:00")),
+ toDate: new Date(timeStrToIntVal("17:15:00")),
+ event: "birthday",
+ employee: "KL",
+ tariff: "X",
+ note: "happy birthday!",
+ duration: 105 * 60 * 1000, // 105 minutes
+ dayInWeekIdx: 4,
+ });
+
+ result.data.forEach(day => {
+ expect(day.from).toBeTruthy()
+ expect(day.to).toBeTruthy()
+ expect(day.fromDate).toBeTruthy()
+ expect(day.toDate).toBeTruthy()
+ expect(day.event).toBeTruthy()
+ expect(day.employee).toBeTruthy()
+ expect(day.tariff).toBeTruthy()
+ expect(day.duration).toBeGreaterThan(0)
+ expect(day.dayInWeekIdx).toBeGreaterThanOrEqual(0)
+ })
+});
+
+
+test('extractSpreadsheetData with no weekend', () => {
+ const record1Shift = ensureValidDayColumn(4);
+ const record2Shift = ensureValidDayColumn(0);
+ const note1Shift = ensureValidDayColumn(2);
+
+ const sheet = (new Sheet())
+ .addHeader()
+ .addEmptyRows(3)
+ .addEmptyDataRows(4)
+ .addEmptyRows(2)
+ .addRows([
+ [...emptyDaysForRow(record1Shift), TTime("15:30:00"), TTime("17:15:00"), "birthday;L", "KL;L", "X;L", "happy birthday!;;happy birthday!"],
+ [],
+ [...emptyDaysForRow(record2Shift), TTime("12:30:00"), TTime("13:00:00"), "", "", "", ""],
+ [],
+ ])
+ .addEmptyDataRows(4)
+ .addEmptyRows(6)
+ .addEmptyDataRows(2)
+ .addRow([...emptyDaysForRow(note1Shift), "day", "this", "78", "a", "bottom", "note"])
+ .addEmptyRows(3)
+
+ const result = extractSpreadsheetData(sheet);
+
+ expect(result.valid).toBe(false);
+ // weekday
+ expect(result.weekday.valid).toBe(true);
+ expect(result.weekday.from).toBeGreaterThan(1);
+ expect(result.weekday.to).toBeGreaterThan(result.weekday.from);
+ expect(result.weekday.length).toStrictEqual(result.weekday.to - result.weekday.from + 1);
+ // weekend
+ expect(result.weekend.valid).toBe(false);
+ expect(result.weekend.from).toStrictEqual(-1);
+ expect(result.weekend.to).toStrictEqual(-1);
+ expect(result.weekend.length).toStrictEqual(-1);
+ // notes
+ expect(result.notes).toHaveLength(0);
+ // data
+ expect(result.data).toHaveLength(2);
+ expect(result.data[0].dayInWeekIdx).toEqual(record1Shift);
+ expect(result.data[1].dayInWeekIdx).toEqual(record2Shift);
+
+ // full day
+ expect(result.data[0]).toEqual({
+ from: "15:30:00",
+ to: "17:15:00",
+ fromDate: new Date(timeStrToIntVal("15:30:00")),
+ toDate: new Date(timeStrToIntVal("17:15:00")),
+ event: "birthday",
+ employee: "KL",
+ tariff: "X",
+ note: "happy birthday!",
+ duration: 105 * 60 * 1000, // 105 minutes
+ dayInWeekIdx: 4,
+ });
+
+ // day with times only
+ expect(result.data[1]).toEqual({
+ from: "12:30:00",
+ to: "13:00:00",
+ fromDate: new Date(timeStrToIntVal("12:30:00")),
+ toDate: new Date(timeStrToIntVal("13:00:00")),
+ event: "",
+ employee: "",
+ tariff: "",
+ note: "",
+ duration: 30 * 60 * 1000, // 30 minutes
+ dayInWeekIdx: 0,
+ });
+});
+
+
+test('extractSpreadsheetData with no header', () => {
+ const record1Shift = ensureValidDayColumn(4);
+ const note1Shift = ensureValidDayColumn(2);
+
+ const sheet = (new Sheet())
+ .addEmptyRows(3)
+ .addEmptyDataRows(4)
+ .addEmptyRows(2)
+ .addRows([
+ [...emptyDaysForRow(record1Shift), TTime("15:30:00"), TTime("17:15:00"), "birthday;L", "KL;L", "X;L", "happy birthday!;;happy birthday!"],
+ [],
+ ])
+ .addEmptyDataRows(4)
+ .addEmptyRows(6)
+ .addEmptyDataRows(2)
+ .addRow([...emptyDaysForRow(note1Shift), "day", "this", "78", "a", "bottom", "note"])
+ .addEmptyRows(3)
+
+ const result = extractSpreadsheetData(sheet);
+
+ expect(result.valid).toBe(false);
+ // weekday
+ expect(result.weekday.valid).toBe(false);
+ expect(result.weekday.from).toStrictEqual(-1);
+ expect(result.weekday.to).toStrictEqual(-1);
+ expect(result.weekday.length).toStrictEqual(-1);
+ // weekend
+ expect(result.weekend.valid).toBe(false);
+ expect(result.weekend.from).toStrictEqual(-1);
+ expect(result.weekend.to).toStrictEqual(-1);
+ expect(result.weekend.length).toStrictEqual(-1);
+ // notes
+ expect(result.notes).toHaveLength(0);
+ // data
+ expect(result.data).toHaveLength(0);
+});
+
+
+test.each([
+ [new Sheet().addEmptyRows(1)],
+ [new Sheet().addEmptyRows(1000)],
+ [new Sheet().addEmptyDataRows(100)],
+ [new Sheet().addEmptyDataRows(3).addEmptyDataRows(100).addEmptyDataRows(3)],
+ // with text
+ [(new Sheet())
+ .addEmptyDataRows(20)
+ .addRow("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.".split(" "))
+ .addRow("Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.".split(" "))
+ .addRow("Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.".split(" "))
+ ],
+ // with missing header
+ [(new Sheet())
+ .addEmptyRows(3)
+ .addEmptyDataRows(4)
+ .addEmptyRows(2)
+ .addRows([
+ [...emptyDaysForRow(ensureValidDayColumn(4)), TTime("15:30:00"), TTime("17:15:00"), "birthday;L", "KL;L", "X;L", "happy birthday!;;happy birthday!"],
+ [],
+ ])
+ .addEmptyDataRows(4)
+ .addEmptyRows(6)
+ .addEmptyDataRows(2)
+ .addRow([...emptyDaysForRow(ensureValidDayColumn(2)), "day", "this", "78", "a", "bottom", "note"])
+ .addEmptyRows(3)
+ ]
+])('extractSpreadsheetData should not extract data on empty or invalid sheet', (sheet) => {
+ const result = extractSpreadsheetData(sheet);
+
+ expect(result.valid).toBe(false);
+ // weekday
+ expect(result.weekday.valid).toBe(false);
+ expect(result.weekday.from).toStrictEqual(-1);
+ expect(result.weekday.to).toStrictEqual(-1);
+ expect(result.weekday.length).toStrictEqual(-1);
+ // weekend
+ expect(result.weekend.valid).toBe(false);
+ expect(result.weekend.from).toStrictEqual(-1);
+ expect(result.weekend.to).toStrictEqual(-1);
+ expect(result.weekend.length).toStrictEqual(-1);
+ // notes
+ expect(result.notes).toHaveLength(0);
+ // data
+ expect(result.data).toHaveLength(0);
+});
+
+
+
+test('extractSpreadsheetData with max empty rows for days and weekends', () => {
+ const note1Shift = ensureValidDayColumn(2);
+ const note2Shift = ensureValidDayColumn(1, true);
+
+ const sheet = (new Sheet())
+ .addEmptyRows(3)
+ .addHeader()
+ .addEmptyDataRows(150)
+ .addRow([...emptyDaysForRow(note1Shift), "day", "this", "78", "a", "bottom", "note"])
+ .addEmptyRows(2)
+ .addHeader(true) // weekend
+ .addEmptyDataRows(150)
+ .addRow([...emptyDaysForRow(note2Shift), "day", "this", "a", "weekend", "bottom", "note"])
+ .addEmptyRows(100)
+
+ const result = extractSpreadsheetData(sheet);
+
+
+ expect(result.valid).toBe(true);
+ // weekday
+ expect(result.weekday.valid).toBe(true);
+ expect(result.weekday.from).toStrictEqual(5);
+ expect(result.weekday.to).toStrictEqual(154);
+ expect(result.weekday.length).toStrictEqual(150);
+ // weekend
+ expect(result.weekend.valid).toBe(true);
+ expect(result.weekend.from).toStrictEqual(159);
+ expect(result.weekend.to).toStrictEqual(308);
+ expect(result.weekend.length).toStrictEqual(150);
+ // notes
+ expect(result.notes).toHaveLength(2);
+ expect(result.notes[0].dayInWeekIdx).toEqual(note1Shift);
+ expect(result.notes[0].values).toEqual(["day", "this", "78", "a", "bottom", "note"]);
+ expect(result.notes[1].dayInWeekIdx).toEqual(dayColumnToDayIdx(note2Shift, true));
+ expect(result.notes[1].values).toEqual(["day", "this", "a", "weekend", "bottom", "note"]);
+ // data
+ expect(result.data).toHaveLength(0)
+});
+
diff --git a/__tests__/Utils/SSExtract_rows.js b/__tests__/Utils/SSExtract_rows.js
new file mode 100644
index 0000000..8d597f4
--- /dev/null
+++ b/__tests__/Utils/SSExtract_rows.js
@@ -0,0 +1,227 @@
+import {
+ asNotesData,
+ asDayData,
+ detectNotesWithData_,
+ detectDaysWithData_,
+ isMetadataRow_,
+ isDayRowByValidation_,
+ isDayRowByBackground_,
+} from "./Utils-bundle"
+
+import {
+ TestValidation
+} from "./sheet_mock"
+
+const fullDayNotesRow = ["day", "this", 78, "a", "bottom", "note"];
+const expectedFullDayNotesRow = ["day", "this", "78", "a", "bottom", "note"];
+const sparseDayNotesRow = ["", "", "", "", "", "note"];
+const emptyDayRow = ["", "", "", "", "", ""];
+
+
+const fromDate = new Date(0);
+const toDate = new Date(0);
+
+fromDate.setHours(15);
+fromDate.setMinutes(30);
+fromDate.setSeconds(28);
+
+toDate.setHours(16);
+toDate.setMinutes(15);
+toDate.setSeconds(0);
+
+
+const dataRow = [fromDate.getTime(), toDate.getTime(), "birthday", "KL", "X", "happy birthday!"];
+const displayDataRow = ["15:30:28", "16:15:00", "birthday", "KL", "X", "happy birthday!"];
+
+test.each([
+ [undefined, 0, 6, {
+ dayInWeekIdx: 0,
+ values: []
+ }],
+ [[], 0, 6, {
+ dayInWeekIdx: 0,
+ values: []
+ }],
+ [fullDayNotesRow, 0, 6, {
+ dayInWeekIdx: 0,
+ values: expectedFullDayNotesRow
+ }],
+ [[...emptyDayRow, ...fullDayNotesRow, ...emptyDayRow, ...emptyDayRow], 1, 6, {
+ dayInWeekIdx: 1,
+ values: expectedFullDayNotesRow
+ }],
+ [[...emptyDayRow, ...emptyDayRow, ...emptyDayRow, ...fullDayNotesRow], 3, 6, {
+ dayInWeekIdx: 3,
+ values: expectedFullDayNotesRow
+ }],
+ [[...sparseDayNotesRow, ...emptyDayRow, ...emptyDayRow, ...fullDayNotesRow], 3, 6, {
+ dayInWeekIdx: 3,
+ values: expectedFullDayNotesRow
+ }],
+ [[...emptyDayRow, ...emptyDayRow, ...sparseDayNotesRow, ...emptyDayRow], 2, 6, {
+ dayInWeekIdx: 2,
+ values: sparseDayNotesRow
+ }],
+ [[...emptyDayRow, ...emptyDayRow, ...sparseDayNotesRow, ...emptyDayRow], 4, 4, {
+ dayInWeekIdx: 4,
+ values: ["", "note", "", ""]
+ }],
+])('asNotesData', (notesRow, dayInWeekIdx, dayWidth, expected) => {
+ expect(asNotesData(notesRow, dayInWeekIdx, dayWidth)).toEqual(expected);
+});
+
+test('detectNotesWithData_', () => {
+ expect(detectNotesWithData_(
+ [...emptyDayRow, ...fullDayNotesRow, ...emptyDayRow, ...sparseDayNotesRow, ...sparseDayNotesRow, ...emptyDayRow, ...emptyDayRow, ...fullDayNotesRow],
+ 6, 7
+ )).toEqual([1, 3, 4]);
+
+ expect(detectNotesWithData_(
+ ["", 0, "", "", "", null],
+ 3, 2
+ )).toEqual([0]);
+ expect(detectNotesWithData_(null, 190, 1789
+ )).toEqual([]);
+});
+
+test('detectDaysWithData_', () => {
+ expect(detectDaysWithData_(
+ [...emptyDayRow, ...fullDayNotesRow, ...emptyDayRow, ...sparseDayNotesRow, ...sparseDayNotesRow, ...emptyDayRow, ...emptyDayRow, ...fullDayNotesRow],
+ [...emptyDayRow, ...fullDayNotesRow, ...emptyDayRow, ...sparseDayNotesRow, ...sparseDayNotesRow, ...emptyDayRow, ...emptyDayRow, ...fullDayNotesRow],
+
+ 6, 7
+ )).toEqual([]);
+
+ expect(detectDaysWithData_(
+ [...fullDayNotesRow, ...dataRow, ...emptyDayRow, ...sparseDayNotesRow, ...dataRow],
+ [...fullDayNotesRow, ...displayDataRow, ...emptyDayRow, ...sparseDayNotesRow, ...displayDataRow],
+ 6, 5
+ )).toEqual([1, 4]);
+
+ expect(detectDaysWithData_(
+ [...fullDayNotesRow, ...dataRow, ...emptyDayRow],
+ [...fullDayNotesRow, ...displayDataRow, ...emptyDayRow],
+ 6, 5
+ )).toEqual([1]);
+
+ expect(detectDaysWithData_(null, null, 190, 1789
+ )).toEqual([]);
+});
+
+
+test.each([
+ {
+ testName: "no data",
+ valuesRow: undefined,
+ displayValuesRow: undefined,
+ dayInWeekIdx: 1,
+ expected: {
+ dayInWeekIdx: 1,
+ employee: "",
+ event: "",
+ from: "",
+ note: "",
+ tariff: "",
+ to: "",
+ },
+ noDatesExpected: true
+ },
+ {
+ testName: "invalid row data still recorded, but without times",
+ valuesRow: fullDayNotesRow,
+ displayValuesRow: fullDayNotesRow,
+ dayInWeekIdx: 0,
+ expected: {
+ dayInWeekIdx: 0,
+ from: "day",
+ to: "this",
+ event: "78",
+ employee: "a",
+ tariff: "bottom",
+ note: "note",
+ },
+ noDatesExpected: true
+ },
+ {
+ testName: "valid row data",
+ valuesRow: [...emptyDayRow, ...dataRow],
+ displayValuesRow: [...emptyDayRow, ...displayDataRow],
+ dayInWeekIdx: 1,
+ expected: {
+ dayInWeekIdx: 1,
+ from: "15:30:28",
+ to: "16:15:00",
+ duration: 2672000,
+ event: "birthday",
+ employee: "KL",
+ tariff: "X",
+ note: "happy birthday!",
+ }
+ },
+])('$testName asDayData', ({
+ valuesRow,
+ displayValuesRow,
+ dayInWeekIdx,
+ expected,
+ noDatesExpected
+ }) => {
+ const result = asDayData(valuesRow, displayValuesRow, dayInWeekIdx, 6);
+ if (noDatesExpected) {
+ expect(result.fromDate.getTime()).toBeNaN()
+ expect(result.toDate.getTime()).toBeNaN()
+ expect(result.duration).toBeNaN()
+ delete result.duration;
+ } else {
+ expect(result.fromDate.toString()).toContain(expected.from);
+ expect(result.toDate.toString()).toContain(expected.to);
+ }
+
+ delete result.fromDate;
+ delete result.toDate;
+ expect(result).toEqual(expected);
+});
+
+test.each([
+ [undefined, 6, 5, false],
+ [[], 6, 5, false],
+ [emptyDayRow, 6, 5, false],
+ [fullDayNotesRow, 6, 5, false],
+ [sparseDayNotesRow, 6, 5, false],
+ [dataRow, 6, 5, false],
+ [[...emptyDayRow, ...dataRow, ...sparseDayNotesRow, ...fullDayNotesRow], 6, 5, false],
+
+ [['Od', 'Do', '', '', '', ''], 6, 5, false],
+ [[...fullDayNotesRow, '', '', '', '', 'Pásmo', 'Pozn'], 6, 5, false],
+ [[...fullDayNotesRow, '', '', '', 'Pásmo'], 6, 5, false],
+
+ [['Od', 'Do', 'Událost', 'Kdo', 'Pásmo', 'Pozn'], 6, 5, true],
+ [['', 'Do', '', 'Kdo', '', 'Pozn'], 6, 5, true],
+ [[...emptyDayRow, 'Od', '', '', '', '', 'Pozn', ...emptyDayRow, '', 'Do', 'Událost', '', '', 'Pozn', ...sparseDayNotesRow], 6, 5, true],
+])('isMetadataRow_', (values, dayInWeekIdx, dayWidth, expected) => {
+ expect(isMetadataRow_(values, dayInWeekIdx, dayWidth)).toEqual(expected);
+});
+
+test.each([
+ [undefined, undefined, false],
+ [undefined, "#0aeeff", false],
+ [[], undefined, false],
+ [[], "#0aeeff", false],
+ [["#ffffff", "#0aeeff"], "#0aeeff", false],
+ [["#0aeeff", "#0aeeff"], undefined, false],
+ [["#0aeeff", "#0aeeff"], "#0aeeff", true],
+])('isDayRowByBackground_', (backgrounds, rowColor, expected) => {
+ expect(isDayRowByBackground_(backgrounds, rowColor)).toEqual(expected);
+});
+
+
+test.each([
+ [undefined, false],
+ [[], false],
+ [[null, new TestValidation("L"), null, null,null, null], false],
+ [[null, null, new TestValidation("L"), new TestValidation("L"), new TestValidation("L"), null], true],
+ [[null, null, null, new TestValidation("L")], true],
+])('isDayRowByValidation_', (validations, expected) => {
+ expect(isDayRowByValidation_(validations)).toEqual(expected);
+});
+
+
diff --git a/__tests__/Utils/SSExtract_utils.js b/__tests__/Utils/SSExtract_utils.js
new file mode 100644
index 0000000..43b40cc
--- /dev/null
+++ b/__tests__/Utils/SSExtract_utils.js
@@ -0,0 +1,58 @@
+
+
+import { ensureString, getMaxKeyFromMap, analyzeColorDistribution_ } from "./Utils-bundle"
+
+
+test('getMaxKeyFromMap', () => {
+ expect(getMaxKeyFromMap({
+ "ee": 38,
+ "f": 12,
+ "a": 20,
+ "b": 46,
+ "c": 35,
+ "d": 0,
+ "u": -120
+ })).toBe("b");
+});
+
+test('analyzeColorDistribution_', () => {
+ const backgrounds = [
+ [
+ "", "#bbbbbb", "#cccccc", "#ffffff", "#ffffff",
+ ],
+ [
+ "#ffffff", null, "#ffffff", "#ffffff", "#ffffff",
+ ],
+ [
+ "#aaaaaa", "#cccccc", "#cccccc", "#bbbbbb", "#ffffff",
+ ],
+ [
+ "#dddddd", "#dddddd", "#dddddd", "#dddddd", "#dddddd",
+ ]
+ ];
+
+ expect(analyzeColorDistribution_(backgrounds, 3)).toEqual({
+ "#aaaaaa": 1,
+ "#bbbbbb": 2,
+ "#cccccc": 3,
+ });
+
+ expect(analyzeColorDistribution_()).toEqual({});
+ expect(analyzeColorDistribution_([])).toEqual({});
+
+ expect(getMaxKeyFromMap(analyzeColorDistribution_(backgrounds))).toEqual("#dddddd");
+ expect(getMaxKeyFromMap(analyzeColorDistribution_(backgrounds, 2))).toEqual("#bbbbbb"); // picks one of the highest
+});
+
+test.each([
+ [null, ""],
+ [undefined, ""],
+ ["", ""],
+ [0, "0"],
+ ["0", "0"],
+ ["\n", "\n"],
+ ["string", "string"],
+ [String(), ""]
+])('$input asString', (input, expected ) => {
+ expect(ensureString(input)).toBe(expected);
+});
diff --git a/__tests__/Utils/sheet_mock.js b/__tests__/Utils/sheet_mock.js
new file mode 100644
index 0000000..eb6afa9
--- /dev/null
+++ b/__tests__/Utils/sheet_mock.js
@@ -0,0 +1,195 @@
+import { SpreadsheetApp } from './mocks'
+
+export class TestValidation {
+ constructor(typeShortcut) {
+ this.type = null;
+ if (typeShortcut === "L") {
+ this.type = SpreadsheetApp.DataValidationCriteria.VALUE_IN_LIST;
+ }
+ }
+ getCriteriaType() {
+ return this.type
+ }
+}
+
+export const TTime = (time = "", color = '#fff2cc') => {
+ const parts = time.split(":");
+
+ let value = "", d = null;
+ if (parts.length === 3) {
+ const d = new Date(0);
+ d.setHours(parts[0]);
+ d.setMinutes(parts[1]);
+ d.setSeconds(parts[2]);
+ if (!isNaN(d.getTime())) {
+ value = d.getTime() + "";
+ }
+ }
+
+ if (time !== "" && value === "") {
+ throw "invalid time";
+ }
+
+ return `${value};;${time};${color}`
+}
+
+
+export class Sheet {
+ constructor(data) {
+ this.data = data || [];
+ }
+
+ // implementation
+
+ getMaxRows() {
+ return this.data.length;
+ }
+ getLastRow() {
+ for (let rowIdx = this.data.length - 1; rowIdx >= 0; rowIdx--) {
+ const row = this.data[rowIdx];
+ for (let colIdx = 0; colIdx < row.length; colIdx++) {
+ const value = row[colIdx];
+ if (value !== "") {
+ return rowIdx + 1;
+ }
+ }
+ }
+ return 1;
+ }
+ getRange(row, column, numRows, numColumns) {
+ if (row < 1 || column < 1 || numRows < 1 | numColumns < 1) {
+ throw "invalid arguments";
+ }
+
+ const newData = [];
+
+ const fromRow = row - 1;
+ const fromCol = column - 1;
+
+ for (let rowIdx = fromRow; rowIdx < fromRow + numRows; rowIdx++) {
+ const rowData = this.data[rowIdx];
+ const newRow = []
+ for (let colIdx = fromCol; colIdx < fromCol + numColumns; colIdx++) {
+ const value = (rowData[colIdx] || "");
+ newRow.push(value);
+ }
+ newData.push(newRow);
+ }
+
+ // originally Range type is returned, but this is good for test purposes
+ return new Sheet(newData)
+ }
+
+ getValues() {
+ return this.splitAccordingly(0, (x) => {
+ const res = parseInt(x, 10)
+ if (isNaN(res) || res + "" !== x) {
+ return x;
+ }
+
+ return res;
+ })
+ }
+
+ getDataValidations() {
+ return this.splitAccordingly(1, (x) => {
+ if (x === "") {
+ return null;
+ }
+ return new TestValidation(x);
+ })
+ }
+
+ getDisplayValues() {
+ return this.splitAccordingly(2);
+ }
+
+ getBackgrounds() {
+ return this.splitAccordingly(3);
+ }
+
+ // format value;validations;displayValue;backgroundColor
+ // 2672000;L;15:30:28;#e2f3ff
+ splitAccordingly(idx, valueModifier = (x) => x, delimiter = ";") {
+ const result = [];
+ for (let rowIdx = 0; rowIdx < this.data.length; rowIdx++) {
+ const row = this.data[rowIdx];
+ const resultRow = [];
+ for (let colIdx = 0; colIdx < row.length; colIdx++) {
+ const valueAndMetadata = (row[colIdx] || "").split(delimiter);
+
+ resultRow.push(valueModifier(idx < valueAndMetadata.length ? valueAndMetadata[idx] : ""));
+ }
+ result.push(resultRow);
+ }
+ return result;
+ }
+
+ // test utility functions
+
+ addHeader(isWeekend = false) {
+ const days = isWeekend ? 2 : 5;
+ const header = [];
+ for (let day = 0; day < days; day++) {
+ header.push('Od', 'Do', 'Událost', 'Kdo', 'Pásmo', 'Pozn');
+ }
+ this.data.push(header);
+ return this;
+ }
+
+
+ addEmptyRows(numOfRows) {
+ for (let newRow = 0; newRow < numOfRows; newRow++) {
+ this.data.push([]);
+ }
+ return this;
+ }
+
+ addEmptyDataRows(numOfRows, isWeekend = false) {
+ const days = isWeekend ? 2 : 5;
+ for (let newRow = 0; newRow < numOfRows; newRow++) {
+ const newRow = [];
+
+ for (let day = 0; day < days; day++) {
+ newRow.push(TTime(), TTime(), ';L', ';L', ';L', '');
+ }
+ this.data.push(newRow);
+ }
+ return this;
+ }
+
+ addRow(row) {
+ this.data.push(row)
+ return this;
+ }
+
+
+ addRows(data) {
+ this.data.push(...data)
+ return this;
+ }
+
+ withMinCols(mincols) {
+ for (let rowIdx = 0; rowIdx < this.data.length; rowIdx++) {
+ const row = this.data[rowIdx];
+ for (let colIdx = row.length; colIdx < mincols; colIdx++) {
+ row.push("");
+ }
+ }
+ return this;
+ }
+
+ print() {
+ let toPrint = "";
+ for (let rowIdx = 0; rowIdx < this.data.length; rowIdx++) {
+ toPrint += rowIdx + 1;
+ const row = this.data[rowIdx];
+ for (let colIdx = 0; colIdx < row.length; colIdx++) {
+ toPrint += " " + row[colIdx];
+ }
+ toPrint += "\n";
+ }
+ console.log(toPrint);
+ return this;
+ }
+}
From b6efafb416b08ff747b6d296f72ff4cac85bbf81 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Filip=20K=C5=99epinsk=C3=BD?=
Date: Fri, 3 Jun 2022 12:13:22 +0200
Subject: [PATCH 08/26] do not ouput multiple instances errors when deleting
employee data
---
src/Utils/EmployeeRepository.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/Utils/EmployeeRepository.js b/src/Utils/EmployeeRepository.js
index 32fd0a9..d81b1ea 100644
--- a/src/Utils/EmployeeRepository.js
+++ b/src/Utils/EmployeeRepository.js
@@ -34,13 +34,13 @@ function deleteEmployee(user) { // *wrapper function: treats assistant and emplo
if (result) {
deleteGroupLeader({
employeeEmail: user.email
- });
+ }, true);
deleteGroupActor({
employeeEmail: user.email
- });
+ }, true);
deleteTrigger({
email: user.email
- });
+ }, true);
}
return result;
}
From 7103f2dc313818cec1f6ff9cbafaccef58a7557f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Filip=20K=C5=99epinsk=C3=BD?=
Date: Fri, 3 Jun 2022 13:13:10 +0200
Subject: [PATCH 09/26] log better trigger errors & cosmetics
---
__tests__/Utils/SSExtract.js | 4 ++--
src/SheetRedirect/Triggers.js | 23 +++++++++++++----------
2 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/__tests__/Utils/SSExtract.js b/__tests__/Utils/SSExtract.js
index fc382a1..14f18e3 100644
--- a/__tests__/Utils/SSExtract.js
+++ b/__tests__/Utils/SSExtract.js
@@ -1,5 +1,5 @@
-import { ensureString, extractSpreadsheetData, isDayRowByValidation_ } from "./Utils-bundle"
-import { Sheet, TestValidation, TTime } from "./sheet_mock"
+import { extractSpreadsheetData, } from "./Utils-bundle"
+import { Sheet, TTime } from "./sheet_mock"
const dayWidth = 6;
diff --git a/src/SheetRedirect/Triggers.js b/src/SheetRedirect/Triggers.js
index 42951c5..212ae7a 100644
--- a/src/SheetRedirect/Triggers.js
+++ b/src/SheetRedirect/Triggers.js
@@ -3,7 +3,7 @@
*
* @param id id of spreadsheet
*/
-function resolveTriggers(id) {
+function resolveTriggers (id) {
try {
var userPerm = Utils.getUserPermission();
if (userPerm == Utils.AccessEnums.ADMIN || userPerm == Utils.AccessEnums.LEADER) {
@@ -18,7 +18,7 @@ function resolveTriggers(id) {
}
}
} catch (x) {
- Utils.logError(x);
+ Utils.logError("resolveTriggers on " + id + ": " + JSON.stringify(x));
}
}
@@ -28,7 +28,7 @@ function resolveTriggers(id) {
*
* @param ss spreadsheet for setting triggers
*/
-function resolveOnTrigger(ss, type, functionName) {
+function resolveOnTrigger (ss, type, functionName) {
try {
var email = Utils.getUserEmail();
var triggers = Utils.findTriggers([], {
@@ -67,7 +67,7 @@ function resolveOnTrigger(ss, type, functionName) {
*
* @return {number} number of deleted triggers
*/
-function deleteLowestTrigger() {
+function deleteLowestTrigger () {
var email = Utils.getUserEmail();
var triggers = ScriptApp.getProjectTriggers();
var fileTriggers = Utils.findTriggers([], {
@@ -78,7 +78,7 @@ function deleteLowestTrigger() {
emailSequence: 0
}; // 0 if no triggers installed
- fileTriggers.forEach(function(item) {
+ fileTriggers.forEach(function (item) {
if ((item.emailSequence < lowestTrigger.emailSequence || lowestTrigger.emailSequence == 0) && item.emailSequence != 0) {
lowestTrigger = item;
}
@@ -101,7 +101,7 @@ function deleteLowestTrigger() {
* @param type type of trigger to resolve
* @param functionName name of trigger's funtion to resolve
*/
-function resolveMisplacedTriggers(myGroupsWithEditAttributs, type, functionName){ // recover if trigger is deleted from db
+function resolveMisplacedTriggers (myGroupsWithEditAttributs, type, functionName) { // recover if trigger is deleted from db
var email = Utils.getUserEmail();
var fileTriggers = Utils.convertObjectsToArrayByProperty(Utils.findTriggers([], {
email: email,
@@ -113,17 +113,20 @@ function resolveMisplacedTriggers(myGroupsWithEditAttributs, type, functionName)
for (var j = 0; j < triggers.length; j++) {
var trig = triggers[j];
- if(trig.getHandlerFunction() == functionName && trig.getEventType() == evType) {
+ if (trig.getHandlerFunction() == functionName && trig.getEventType() == evType) {
var fileId = trig.getTriggerSourceId();
var index = fileTriggers.indexOf(fileId);
- if(index < 0 || !Utils.canEditFile(myGroupsWithEditAttributs, fileId)) {
+ if (index < 0 || !Utils.canEditFile(myGroupsWithEditAttributs, fileId)) {
ScriptApp.deleteTrigger(trig);
} else {
fileTriggers.splice(index, 1);
}
}
}
- fileTriggers.forEach(function(item) {
- Utils.deleteTrigger({sheetId: item, type: type});
+ fileTriggers.forEach(function (item) {
+ Utils.deleteTrigger({
+ sheetId: item,
+ type: type
+ });
});
}
From 81e43fb69443111f45da1857c0d1cfa352ff48da Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Filip=20K=C5=99epinsk=C3=BD?=
Date: Fri, 3 Jun 2022 13:25:46 +0200
Subject: [PATCH 10/26] use more of layout validation in onOpen, OnEdit
functions
---
src/SheetRedirect/SSEdit.js | 32 ++++++++++++---------
src/SheetRedirect/SheetsSpecialFunctions.js | 19 +++++++-----
2 files changed, 30 insertions(+), 21 deletions(-)
diff --git a/src/SheetRedirect/SSEdit.js b/src/SheetRedirect/SSEdit.js
index 00aac49..9df21d7 100644
--- a/src/SheetRedirect/SSEdit.js
+++ b/src/SheetRedirect/SSEdit.js
@@ -3,7 +3,7 @@
*
* @param e event send from spreadsheet
*/
-function editMainSheet(e) {
+function editMainSheet (e) {
var sheet = e.source.getActiveSheet();
if (sheet.getName() === 'Rozpis') {
@@ -13,11 +13,14 @@ function editMainSheet(e) {
var rows = e.range.getNumRows();
var cols = e.range.getNumColumns();
- if(rows > 5){ // don't check large quantities == slow
+ if (rows > 5) { // don't check large quantities == slow
return;
}
var layout = Utils.extractSpreadsheetData(sheet);
+ if (!layout.weekday.valid && !layout.weekend.valid) {
+ return;
+ }
for (var j = 0; j < rows; j++) {
var targetRow = row + j;
@@ -25,8 +28,8 @@ function editMainSheet(e) {
for (var i = 0; i < cols && i < 6 * 5 + 2; i++) { // we can delete more rows at once and keep formating, but we can insert only value to one cell
var targetCol = col + i;
- if ((targetRow >= layout.weekday.from && targetRow <= layout.weekday.to && targetCol < 6 * 5 + 1) ||
- (targetRow >= layout.weekend.from && targetRow <= layout.weekend.to && targetCol < 6 * 2 + 1)) { // select our specified area
+ if ((layout.weekday.valid && targetRow >= layout.weekday.from && targetRow <= layout.weekday.to && targetCol < 6 * 5 + 1) ||
+ (layout.weekend.valid && targetRow >= layout.weekend.from && targetRow <= layout.weekend.to && targetCol < 6 * 2 + 1)) { // select our specified area
if (((targetCol + 2) % 6 == 0)) {
employeeChanged(sheet, targetRow, targetCol);
}
@@ -54,7 +57,7 @@ function editMainSheet(e) {
* @param row row of event
* @param col col of event
*/
-function mainEventChanged(e, sheet, row, col) {
+function mainEventChanged (e, sheet, row, col) {
if (e.value && isSelectedMainEvent(e.value)) {
sheet.getRange(row, col, 1, 3).setBackground('#ffffff');
sheet.getRange(row, col + 1, 1, 2).setValue('');
@@ -68,7 +71,7 @@ function mainEventChanged(e, sheet, row, col) {
* @param row row of event
* @param col col of event
*/
-function dateChanged(sheet, row, col) {
+function dateChanged (sheet, row, col) {
var from = sheet.getRange(row, col, 1, 1);
var to = sheet.getRange(row, col + 1, 1, 1);
@@ -85,7 +88,7 @@ function dateChanged(sheet, row, col) {
* @param row row of event
* @param col col of event
*/
-function employeeChanged(sheet, row, col) {
+function employeeChanged (sheet, row, col) {
var background = '#ffffff';
var values = sheet.getRange(row, col - 1, 1, 3).getValues()
@@ -94,11 +97,11 @@ function employeeChanged(sheet, row, col) {
var event = values[0][0];
if (value) {
- if(manager.colors == null)
+ if (manager.colors == null)
manager.colors = getScriptData('colors');
- if(manager.nicks == null)
+ if (manager.nicks == null)
manager.nicks = getScriptData('nicks');
- if(manager.defaultTariff == null)
+ if (manager.defaultTariff == null)
manager.defaultTariff = getScriptData('defaultTariff');
var colors = manager.colors;
@@ -120,7 +123,7 @@ function employeeChanged(sheet, row, col) {
}
}
- if(tariff != values[0][2]){
+ if (tariff != values[0][2]) {
sheet.getRange(row, col + 1).setValue(tariff);
}
@@ -133,9 +136,10 @@ function employeeChanged(sheet, row, col) {
* @param value value of selected field
* @return {boolean} true if selected event is not a client
*/
-function isSelectedMainEvent(value) {
- if(manager.events == null)
- manager.events = getScriptData('events');
+function isSelectedMainEvent (value) {
+ if (manager.events == null) {
+ manager.events = getScriptData('events');
+ }
var events = manager.events;
return events.indexOf(value) > -1;
diff --git a/src/SheetRedirect/SheetsSpecialFunctions.js b/src/SheetRedirect/SheetsSpecialFunctions.js
index a865a61..914eb70 100644
--- a/src/SheetRedirect/SheetsSpecialFunctions.js
+++ b/src/SheetRedirect/SheetsSpecialFunctions.js
@@ -52,16 +52,21 @@ function toast(spreadsheet,message){
*/
function checkAssistantDuplicities(layoutAndData){
toast(SpreadsheetApp.getActive(), 'Kontrola duplicit...');
- var sheet = SpreadsheetApp.getActive().getSheetByName('Rozpis');
- var width = 6; // num of columns per day
- var messages = '';
+ const sheet = SpreadsheetApp.getActive().getSheetByName('Rozpis');
+ const width = 6; // num of columns per day
+ let messages = '';
- for (var i = 1; i < 6; i++) {
- messages += checkDayDuplicities(sheet, layoutAndData.weekday.from, i, layoutAndData.weekday.length,width);
+
+ if (layoutAndData.weekday.valid) {
+ for (var i = 1; i < 6; i++) {
+ messages += checkDayDuplicities(sheet, layoutAndData.weekday.from, i, layoutAndData.weekday.length,width);
+ }
}
- for (var i = 1; i < 3; i++) {
- messages += checkDayDuplicities(sheet, layoutAndData.weekend.from, i, layoutAndData.weekend.length, width);
+ if (layoutAndData.weekend.valid) {
+ for (var i = 1; i < 3; i++) {
+ messages += checkDayDuplicities(sheet, layoutAndData.weekend.from, i, layoutAndData.weekend.length, width);
+ }
}
if(messages){
From b345af412612ed697b95810994bc7269a02b086d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Filip=20K=C5=99epinsk=C3=BD?=
Date: Fri, 3 Jun 2022 13:59:23 +0200
Subject: [PATCH 11/26] default to first sheet if Rozpis not found
---
src/Billing/appsscript.json | 2 +-
src/CalendarAndFilesScheduler/SS.js | 3 ++-
src/CalendarAndFilesScheduler/appsscript.json | 2 +-
src/Create/appsscript.json | 2 +-
src/Delete/appsscript.json | 2 +-
src/EmailSender/Sender.js | 2 +-
src/EmailSender/appsscript.json | 2 +-
src/PdfBackuper/appsscript.json | 2 +-
src/RenameGroup/Files.js | 2 +-
src/RenameGroup/appsscript.json | 2 +-
src/SheetRedirect/OnOpenSheet.js | 2 +-
src/SheetRedirect/SSLoad.js | 2 +-
src/SheetRedirect/SSScripts.js | 2 +-
src/SheetRedirect/SheetsSpecialFunctions.js | 11 ++++++-----
src/SheetRedirect/appsscript.json | 2 +-
src/Statistics/appsscript.json | 2 +-
src/TableScript/appsscript.json | 2 +-
src/Update/appsscript.json | 2 +-
src/Utils/SpreadSheet.js | 2 +-
19 files changed, 25 insertions(+), 23 deletions(-)
diff --git a/src/Billing/appsscript.json b/src/Billing/appsscript.json
index cebb41b..cef8503 100644
--- a/src/Billing/appsscript.json
+++ b/src/Billing/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 36
+ "version": 66
}
]
},
diff --git a/src/CalendarAndFilesScheduler/SS.js b/src/CalendarAndFilesScheduler/SS.js
index 846c004..9e63573 100644
--- a/src/CalendarAndFilesScheduler/SS.js
+++ b/src/CalendarAndFilesScheduler/SS.js
@@ -34,7 +34,8 @@ function correctProtections() {
}).forEach(function(file) {
var sheet;
try {
- sheet = Utils.openSpreadsheet(file.id).getSheetByName('Rozpis');
+ const ss = Utils.openSpreadsheet(file.id);
+ sheet = ss.getSheetByName('Rozpis') || ss.getSheets()[0];
if (sheet == null) {
return;
diff --git a/src/CalendarAndFilesScheduler/appsscript.json b/src/CalendarAndFilesScheduler/appsscript.json
index 735de6b..5453a4d 100644
--- a/src/CalendarAndFilesScheduler/appsscript.json
+++ b/src/CalendarAndFilesScheduler/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 64
+ "version": 66
}
]
},
diff --git a/src/Create/appsscript.json b/src/Create/appsscript.json
index 997e183..cef8503 100644
--- a/src/Create/appsscript.json
+++ b/src/Create/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 64
+ "version": 66
}
]
},
diff --git a/src/Delete/appsscript.json b/src/Delete/appsscript.json
index 997e183..cef8503 100644
--- a/src/Delete/appsscript.json
+++ b/src/Delete/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 64
+ "version": 66
}
]
},
diff --git a/src/EmailSender/Sender.js b/src/EmailSender/Sender.js
index 3f1d178..1db7fbe 100644
--- a/src/EmailSender/Sender.js
+++ b/src/EmailSender/Sender.js
@@ -17,7 +17,7 @@ function processClients(formObject, opts) {
var body = formObject['textArea'] == null ? '' : formObject['textArea'];
var sheetId = opts.sheetId;
var mainSS = SpreadsheetApp.openById(sheetId);
- var mainSheet = mainSS.getSheetByName('Rozpis');
+ var mainSheet = mainSS.getSheetByName('Rozpis') || mainSS.getSheets()[0];
var layoutAndData = Utils.extractSpreadsheetData(mainSheet);
var payloadSS = SpreadsheetApp.create(mainSS.getName());
diff --git a/src/EmailSender/appsscript.json b/src/EmailSender/appsscript.json
index 997e183..cef8503 100644
--- a/src/EmailSender/appsscript.json
+++ b/src/EmailSender/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 64
+ "version": 66
}
]
},
diff --git a/src/PdfBackuper/appsscript.json b/src/PdfBackuper/appsscript.json
index 997e183..cef8503 100644
--- a/src/PdfBackuper/appsscript.json
+++ b/src/PdfBackuper/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 64
+ "version": 66
}
]
},
diff --git a/src/RenameGroup/Files.js b/src/RenameGroup/Files.js
index f2c1981..3393f68 100644
--- a/src/RenameGroup/Files.js
+++ b/src/RenameGroup/Files.js
@@ -19,7 +19,7 @@ function renameFile(file, newGroupName) {
return false;
}
- const sheet = spreadSheet.getSheetByName('Rozpis');
+ const sheet = spreadSheet.getSheetByName('Rozpis') || spreadSheet.getSheets()[0];
if (sheet == null) {
return false;
}
diff --git a/src/RenameGroup/appsscript.json b/src/RenameGroup/appsscript.json
index 03bf6af..321cccd 100644
--- a/src/RenameGroup/appsscript.json
+++ b/src/RenameGroup/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 64
+ "version": 66
}
]
},
diff --git a/src/SheetRedirect/OnOpenSheet.js b/src/SheetRedirect/OnOpenSheet.js
index 92ea308..aa010c4 100644
--- a/src/SheetRedirect/OnOpenSheet.js
+++ b/src/SheetRedirect/OnOpenSheet.js
@@ -12,7 +12,7 @@ function onOpenSheet() {
initializeData();
}
- var sheet = spreadSheet.getSheetByName('Rozpis');
+ var sheet = spreadSheet.getSheetByName('Rozpis') || spreadSheet.getSheets()[0];
var layoutAndData = Utils.extractSpreadsheetData(sheet);
// alert when sheet is in incompatible format
diff --git a/src/SheetRedirect/SSLoad.js b/src/SheetRedirect/SSLoad.js
index 59f613b..d3c7410 100644
--- a/src/SheetRedirect/SSLoad.js
+++ b/src/SheetRedirect/SSLoad.js
@@ -29,7 +29,7 @@ function updateSpreadSheet(spreadSheet, layoutAndData, checkIntegrity) {
var rules = makeRules(arrays);
var width = 6; // num of columns per day
- var sheet = spreadSheet.getSheetByName('Rozpis');
+ var sheet = spreadSheet.getSheetByName('Rozpis') || spreadSheet.getSheets()[0];
if (layoutAndData.weekday.valid) {
diff --git a/src/SheetRedirect/SSScripts.js b/src/SheetRedirect/SSScripts.js
index bd1b5cc..2575c87 100644
--- a/src/SheetRedirect/SSScripts.js
+++ b/src/SheetRedirect/SSScripts.js
@@ -8,7 +8,7 @@
*/
function refreshAssistantsSheets(spreadSheet, layoutAndData, actors, eventsNames) {
spreadSheet = spreadSheet ? spreadSheet : SpreadsheetApp.getActiveSpreadsheet();
- var mainSheet = spreadSheet.getSheetByName('Rozpis');
+ var mainSheet = spreadSheet.getSheetByName('Rozpis') || spreadSheet.getSheets()[0];
if(actors == null){
return;
}
diff --git a/src/SheetRedirect/SheetsSpecialFunctions.js b/src/SheetRedirect/SheetsSpecialFunctions.js
index 914eb70..4460976 100644
--- a/src/SheetRedirect/SheetsSpecialFunctions.js
+++ b/src/SheetRedirect/SheetsSpecialFunctions.js
@@ -51,20 +51,21 @@ function toast(spreadsheet,message){
*
*/
function checkAssistantDuplicities(layoutAndData){
- toast(SpreadsheetApp.getActive(), 'Kontrola duplicit...');
- const sheet = SpreadsheetApp.getActive().getSheetByName('Rozpis');
+ const ss = SpreadsheetApp.getActive()
+ toast(ss, 'Kontrola duplicit...');
+ const sheet = ss.getSheetByName('Rozpis') || ss.getSheets()[0];
const width = 6; // num of columns per day
let messages = '';
if (layoutAndData.weekday.valid) {
- for (var i = 1; i < 6; i++) {
+ for (let i = 1; i < 6; i++) {
messages += checkDayDuplicities(sheet, layoutAndData.weekday.from, i, layoutAndData.weekday.length,width);
}
}
if (layoutAndData.weekend.valid) {
- for (var i = 1; i < 3; i++) {
+ for (let i = 1; i < 3; i++) {
messages += checkDayDuplicities(sheet, layoutAndData.weekend.from, i, layoutAndData.weekend.length, width);
}
}
@@ -72,7 +73,7 @@ function checkAssistantDuplicities(layoutAndData){
if(messages){
alertUi('Byly nalezeny tyto nesrovnalosti :\n\n' + messages);
}else{
- toast(SpreadsheetApp.getActive(), 'Nenalezeny žádné duplicity.');
+ toast(ss, 'Nenalezeny žádné duplicity.');
}
}
diff --git a/src/SheetRedirect/appsscript.json b/src/SheetRedirect/appsscript.json
index 997e183..cef8503 100644
--- a/src/SheetRedirect/appsscript.json
+++ b/src/SheetRedirect/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 64
+ "version": 66
}
]
},
diff --git a/src/Statistics/appsscript.json b/src/Statistics/appsscript.json
index 997e183..cef8503 100644
--- a/src/Statistics/appsscript.json
+++ b/src/Statistics/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 64
+ "version": 66
}
]
},
diff --git a/src/TableScript/appsscript.json b/src/TableScript/appsscript.json
index 997e183..cef8503 100644
--- a/src/TableScript/appsscript.json
+++ b/src/TableScript/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 64
+ "version": 66
}
]
},
diff --git a/src/Update/appsscript.json b/src/Update/appsscript.json
index 997e183..cef8503 100644
--- a/src/Update/appsscript.json
+++ b/src/Update/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 64
+ "version": 66
}
]
},
diff --git a/src/Utils/SpreadSheet.js b/src/Utils/SpreadSheet.js
index c9c275d..6a7af27 100644
--- a/src/Utils/SpreadSheet.js
+++ b/src/Utils/SpreadSheet.js
@@ -71,7 +71,7 @@ function getAllSpreadSheetData(from, to) {
}
}
- result.push.apply(result, extractSpreadSheet(ss.getSheetByName('Rozpis'), extractDays));
+ result.push.apply(result, extractSpreadSheet(ss.getSheetByName('Rozpis') || ss.getSheets()[0], extractDays));
if (stopTimer() / 1000 > 250){ // more than 250s -- abort - 50 sec left for the rest of the script wchich is billing/stat
throw {timeout: true};
From 2b2034ccf582412694239add57770ea4a3eb91f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Filip=20K=C5=99epinsk=C3=BD?=
Date: Sun, 5 Jun 2022 20:29:33 +0200
Subject: [PATCH 12/26] introduce new extractAllSpreadsheetData and use it in
Billing/Statistics
- refactoring (mainly createStats and writeStats)
- fix bug in OnOpen and OnEdit functions
---
src/Billing/WriteBilling.js | 43 +++---
src/Billing/WriteUtils.js | 6 +-
src/Billing/appsscript.json | 2 +-
src/CalendarAndFilesScheduler/appsscript.json | 2 +-
src/Create/appsscript.json | 2 +-
src/Delete/appsscript.json | 2 +-
src/EmailSender/Sender.js | 2 +-
src/EmailSender/appsscript.json | 2 +-
src/PdfBackuper/PdfBackuper.js | 42 +++---
src/PdfBackuper/appsscript.json | 2 +-
src/RenameGroup/appsscript.json | 2 +-
src/SheetRedirect/OnOpenSheet.js | 25 ++--
src/SheetRedirect/appsscript.json | 2 +-
src/Statistics/WriteStats.js | 126 ++++++++++--------
src/Statistics/appsscript.json | 2 +-
src/TableScript/appsscript.json | 2 +-
src/Update/appsscript.json | 2 +-
src/Utils/Date.js | 16 +--
src/Utils/SpreadSheet.js | 110 +++++----------
19 files changed, 180 insertions(+), 212 deletions(-)
diff --git a/src/Billing/WriteBilling.js b/src/Billing/WriteBilling.js
index 0764daa..4f97837 100644
--- a/src/Billing/WriteBilling.js
+++ b/src/Billing/WriteBilling.js
@@ -7,11 +7,11 @@
* @return {string} url of new spreadsheet
*/
function createBilling(from, to, client) {
- var spreadsheetData = Utils.getAllSpreadSheetData(from, to);
- var ss = Utils.createSpreadsheet({
+ const spreadsheetData = Utils.extractAllSpreadsheetData(from, to);
+ const ss = Utils.createSpreadsheet({
type: 'Fakturace'
});
- var sheet = ss.getActiveSheet();
+ const sheet = ss.getActiveSheet();
sheet.setName('Fakturace');
writeToCell(sheet, 1, 1, 'Fakturace pro:');
@@ -41,39 +41,40 @@ function createBilling(from, to, client) {
* @param client name of client
*/
function writeBilling(spreadsheetData, sheet, client) {
- var result = {};
- var tariffs = Utils.findTariffs();
- var total = 0;
- var i = 4;
+ const durationsForTarriffs = {};
+ const tariffs = Utils.findTariffs();
+ let total = 0;
+ let i = 4;
spreadsheetData.forEach(function(item) {
- if (item.tariff && item.event && item.event == client) {
- if (!result[item.tariff]) {
- result[item.tariff] = 0;
+ if (item.tariff && item.event && item.event === client) {
+ if (!durationsForTarriffs[item.tariff]) {
+ durationsForTarriffs[item.tariff] = 0;
}
- result[item.tariff] += item.duration;
+ durationsForTarriffs[item.tariff] += item.duration;
}
});
- tariffs.forEach(function(item) {
- if (result[item.shortcut]) {
- var subtotal;
- var hours = result[item.shortcut] / (60 * 60 * 1000);
+ tariffs.forEach(function(tariff) {
+ if (durationsForTarriffs[tariff.shortcut]) {
+ let subtotal;
+ let hours = durationsForTarriffs[tariff.shortcut] / (60 * 60 * 1000);
- hours = (hours % 1 > 0.5 || hours % 1 == 0) ? Math.ceil(hours) : (Math.floor(hours) + 0.5); // zaokrouhli na nejblizsi pul hodinu
+ // TODO test
+ hours = (hours % 1 > 0.5 || hours % 1 === 0) ? Math.ceil(hours) : (Math.floor(hours) + 0.5); // zaokrouhli na nejblizsi pul hodinu
- subtotal = item.price * hours;
+ subtotal = tariff.price * hours;
total += subtotal;
- writeToCell(sheet, i, 1, item.name);
- writeToCell(sheet, i, 2, item.shortcut);
+ writeToCell(sheet, i, 1, tariff.name);
+ writeToCell(sheet, i, 2, tariff.shortcut);
writeToCellSpec(sheet, i, 3, {
value: hours,
oneDigitFormat: true
});
- writeToCell(sheet, i, 4, item.price);
+ writeToCell(sheet, i, 4, tariff.price);
writeToCellSpec(sheet, i, 5, {
value: subtotal,
roundPrice: true,
@@ -82,7 +83,7 @@ function writeBilling(spreadsheetData, sheet, client) {
});
i++;
- };
+ }
});
writeToCell(sheet, ++i, 4, 'Součet');
diff --git a/src/Billing/WriteUtils.js b/src/Billing/WriteUtils.js
index 955bb80..98fd54c 100644
--- a/src/Billing/WriteUtils.js
+++ b/src/Billing/WriteUtils.js
@@ -7,9 +7,9 @@
* @param obj obj with input data and its format (as {value: xx, color: xx, isDuration: xx, roundPrice: xx, oneDigitFormat: xx, twoDigitFormat: xx})
*/
function writeToCellSpec(sheet, row, col, obj) {
- var cell = sheet.getRange(row, col);
- var value = obj.value;
- var color = obj.color;
+ const cell = sheet.getRange(row, col);
+ let value = obj.value;
+ const color = obj.color;
if (obj.isDuration === true) {
cell.setNumberFormat('[h]:mm:ss');
diff --git a/src/Billing/appsscript.json b/src/Billing/appsscript.json
index cef8503..73b7786 100644
--- a/src/Billing/appsscript.json
+++ b/src/Billing/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 66
+ "version": 70
}
]
},
diff --git a/src/CalendarAndFilesScheduler/appsscript.json b/src/CalendarAndFilesScheduler/appsscript.json
index 5453a4d..21f9bf7 100644
--- a/src/CalendarAndFilesScheduler/appsscript.json
+++ b/src/CalendarAndFilesScheduler/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 66
+ "version": 70
}
]
},
diff --git a/src/Create/appsscript.json b/src/Create/appsscript.json
index cef8503..73b7786 100644
--- a/src/Create/appsscript.json
+++ b/src/Create/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 66
+ "version": 70
}
]
},
diff --git a/src/Delete/appsscript.json b/src/Delete/appsscript.json
index cef8503..73b7786 100644
--- a/src/Delete/appsscript.json
+++ b/src/Delete/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 66
+ "version": 70
}
]
},
diff --git a/src/EmailSender/Sender.js b/src/EmailSender/Sender.js
index 1db7fbe..15bd30f 100644
--- a/src/EmailSender/Sender.js
+++ b/src/EmailSender/Sender.js
@@ -10,7 +10,7 @@ function processClients(formObject, opts) {
emails = emails.filter(function(email){
return email.indexOf("@") > -1;
});
- if(emails.length == 0){
+ if(emails.length === 0){
return {success: 'Nebyl vybrán žádný email pro odeslání!'};
}
diff --git a/src/EmailSender/appsscript.json b/src/EmailSender/appsscript.json
index cef8503..73b7786 100644
--- a/src/EmailSender/appsscript.json
+++ b/src/EmailSender/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 66
+ "version": 70
}
]
},
diff --git a/src/PdfBackuper/PdfBackuper.js b/src/PdfBackuper/PdfBackuper.js
index 42dc91e..a9ec583 100644
--- a/src/PdfBackuper/PdfBackuper.js
+++ b/src/PdfBackuper/PdfBackuper.js
@@ -1,29 +1,29 @@
-function backupToPdf(from, to) {
- var time = new Date().toISOString();
- var ROZPIS = 'Rozpis'
+function backupToPdf (from, to) {
+ const time = new Date().toISOString();
+ const ROZPIS = 'Rozpis'
- var folder = DriveApp.createFolder('Záloha_' + time);
+ const folder = DriveApp.createFolder('Záloha_' + time);
- var tmpSS = SpreadsheetApp.create('Tmp');
- var tmpSSId = tmpSS.getId();
- var tmpSSAsFile = DriveApp.getFileById(tmpSSId);
+ const tmpSS = SpreadsheetApp.create('Tmp');
+ const tmpSSId = tmpSS.getId();
+ const tmpSSAsFile = DriveApp.getFileById(tmpSSId);
try {
const stopTimer = Utils.measureTime();
- Utils.findFiles([], {
+ Utils.findFiles([], {
type: ROZPIS
- }).filter(function(file) {
- return Utils.isWeekWithinDates(from, to, file.year, file.week);
- }).forEach(function(file) {
+ }).filter(function (file) {
+ return Utils.isWeekWithinDates(from, to, file.year, file.week);
+ }).forEach(function (file) {
- if (stopTimer() / 1000 > 270){ // more than 270s -- abort
- throw {timeout: true};
+ if (stopTimer() / 1000 > 270) { // more than 270s -- abort
+ throw { timeout: true };
}
- var sourceSS = Utils.openSpreadsheet(file.id);
+ const sourceSS = Utils.openSpreadsheet(file.id);
- var sheet = sourceSS.getSheetByName(ROZPIS);
+ const sheet = sourceSS.getSheetByName(ROZPIS) || sourceSS.getSheets()[0];
if (sheet == null) {
return;
@@ -33,21 +33,21 @@ function backupToPdf(from, to) {
tmpSS.getActiveSheet().setName('Sheet1');
sheet.copyTo(tmpSS).setName(ROZPIS);
- tmpSS.getSheets().forEach(function(tmpSheet) {
- if (tmpSheet.getName() != ROZPIS) {
+ tmpSS.getSheets().forEach(function (tmpSheet) {
+ if (tmpSheet.getName() !== ROZPIS) {
tmpSS.deleteSheet(tmpSheet);
}
});
SpreadsheetApp.flush();
// create pdf and move it to the folder
- var pdf;
+ let pdf;
try {
pdf = DriveApp.createFile(tmpSSAsFile.getAs('application/pdf'));
pdf.setName(sourceSS.getName() + '.pdf');
folder.addFile(pdf);
DriveApp.getRootFolder().removeFile(pdf);
- } catch(e) {
+ } catch (e) {
// cleanup on error
if (pdf != null) {
folder.setTrashed(true);
@@ -55,7 +55,7 @@ function backupToPdf(from, to) {
throw e;
}
});
- } catch(error) {
+ } catch (error) {
folder.setTrashed(true);
throw error;
} finally {
@@ -63,7 +63,7 @@ function backupToPdf(from, to) {
}
if (Utils.isMainAdmin()) {
- var storageFolder = DriveApp.getFolderById(Utils.manager.storageID);
+ const storageFolder = DriveApp.getFolderById(Utils.manager.storageID);
storageFolder.addFolder(folder);
DriveApp.getRootFolder().removeFolder(folder);
}
diff --git a/src/PdfBackuper/appsscript.json b/src/PdfBackuper/appsscript.json
index cef8503..73b7786 100644
--- a/src/PdfBackuper/appsscript.json
+++ b/src/PdfBackuper/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 66
+ "version": 70
}
]
},
diff --git a/src/RenameGroup/appsscript.json b/src/RenameGroup/appsscript.json
index 321cccd..ae40e73 100644
--- a/src/RenameGroup/appsscript.json
+++ b/src/RenameGroup/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 66
+ "version": 70
}
]
},
diff --git a/src/SheetRedirect/OnOpenSheet.js b/src/SheetRedirect/OnOpenSheet.js
index aa010c4..226bff8 100644
--- a/src/SheetRedirect/OnOpenSheet.js
+++ b/src/SheetRedirect/OnOpenSheet.js
@@ -2,8 +2,8 @@
* Reloads data for spreadsheet, generates sheets for assistants and creates menu for admins/leaders
*
*/
-function onOpenSheet() {
- try{
+function onOpenSheet () {
+ try {
var spreadSheet = SpreadsheetApp.getActive();
var isLeader = Utils.getUserPermission() == Utils.AccessEnums.ADMIN || Utils.getUserPermission() == Utils.AccessEnums.LEADER;
@@ -19,20 +19,23 @@ function onOpenSheet() {
if (!layoutAndData.valid) {
var dataTmp = layoutAndData.data;
layoutAndData.data = [];
- alertUi('Rozpis je ve špatném formátu a funkcionalita je omezená! Detekovaný formát:' + JSON.stringify(layoutAndData));
+ Utils.logError(spreadSheet.getName() +': Rozpis je ve špatném formátu a funkcionalita je omezená! Pro správnou funkcionalitu je potřeba opravit. Detekovaný formát: ' + JSON.stringify(layoutAndData));
+ alertUi('Rozpis je ve špatném formátu a funkcionalita je omezená! Pro správnou funkcionalitu je potřeba opravit. Detekovaný formát: ' + JSON.stringify(layoutAndData));
layoutAndData.data = dataTmp;
}
- updateSpreadSheet(spreadSheet, layoutAndData, isLeader && getBoolProp('sheets_redirect_integrity'));
- SpreadsheetApp.flush();
+ if (layoutAndData.valid) {
+ updateSpreadSheet(spreadSheet, layoutAndData, isLeader && getBoolProp('sheets_redirect_integrity'));
+ SpreadsheetApp.flush();
+ }
- if(getBoolProp('sheets_redirect_duplicates')){
+ if (getBoolProp('sheets_redirect_duplicates')) {
checkAssistantDuplicities(layoutAndData);
Utilities.sleep(2000); // just to see last message
}
toast(spreadSheet, 'Hotovo.');
- }catch(x){
+ } catch (x) {
Utils.logError(x);
}
}
@@ -43,16 +46,16 @@ function onOpenSheet() {
* @param spreadSheet spreadSheet object to reload
* @return "cached"(we don't have to get them from slow db) data for reusing
*/
-function initializeData() {
+function initializeData () {
var clients, tariffs, actors, events, sheetRecord, group;
var spreadSheet = SpreadsheetApp.getActive();
try {
sheetRecord = Utils.findFiles(['group'], {
id: spreadSheet.getId()
- },1)[0];
+ }, 1)[0];
group = sheetRecord.group;
- clients = Utils.findGroupClients(['name'], { group: group});
+ clients = Utils.findGroupClients(['name'], { group: group });
events = Utils.findEvents();
clients.push.apply(clients, events);
tariffs = Utils.findTariffs();
@@ -75,7 +78,7 @@ function initializeData() {
* @param tariffs all tariffs with its attributes
* @return {string} returns default tariff
*/
-function getDefaultTariff_(tariffs) {
+function getDefaultTariff_ (tariffs) {
for (var i = 0; i < tariffs.length; i++) {
if (tariffs[i]['default'] == 1) {
return tariffs[i].shortcut;
diff --git a/src/SheetRedirect/appsscript.json b/src/SheetRedirect/appsscript.json
index cef8503..73b7786 100644
--- a/src/SheetRedirect/appsscript.json
+++ b/src/SheetRedirect/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 66
+ "version": 70
}
]
},
diff --git a/src/Statistics/WriteStats.js b/src/Statistics/WriteStats.js
index 7e66581..25c1c85 100644
--- a/src/Statistics/WriteStats.js
+++ b/src/Statistics/WriteStats.js
@@ -6,24 +6,28 @@
* @return {string} url of new spreadsheet
*/
function createStatistics(from, to) {
- var spreadsheetData = Utils.getAllSpreadSheetData(from, to);
- var ss = Utils.createSpreadsheet({
+ let spreadsheetData = Utils.extractAllSpreadsheetData(from, to); // can throw timeout
+ const ss = Utils.createSpreadsheet({
type: 'Statistika'
});
- var clientsSheet = ss.getActiveSheet();
- var clientsSheet2 = ss.insertSheet('Klienti Počet návštěv');
- var assistantsSheet = ss.insertSheet('Asistenti');
- var events = Utils.convertObjectsToArrayByProperty(Utils.findEvents(), 'name');
+ const clientsSheet = ss.getActiveSheet();
+ const clientsSheet2 = ss.insertSheet('Klienti Počet návštěv');
+ const assistantsSheet = ss.insertSheet('Asistenti');
+ const events = Utils.convertObjectsToArrayByProperty(Utils.findEvents(), 'name');
+ const eventsMap = {}
+ for (let i = 0; i < events.length; i++) {
+ eventsMap[events[i]] = true
+ }
clientsSheet.setName('Klienti');
spreadsheetData = spreadsheetData.filter(function(item) {
- return (events.indexOf(item['event']) < 0);
+ return !eventsMap[item['event']];
});
- writeStats(spreadsheetData, clientsSheet, 'event', from, to);
- writeStats(spreadsheetData, clientsSheet2, 'event2', from, to);
- writeStats(spreadsheetData, assistantsSheet, 'employee', from, to);
+ writeStats(spreadsheetData, clientsSheet, 'event', from, to, false);
+ writeStats(spreadsheetData, clientsSheet2, 'event', from, to, true);
+ writeStats(spreadsheetData, assistantsSheet, 'employee', from, to, false);
return ss.getUrl();
}
@@ -35,58 +39,66 @@ function createStatistics(from, to) {
* @param type switches writing stats to different modes
* @param from from which data to write stats
* @param to to which data to write stats
+ * @param onlyCount measure occurences count instead of duration
*/
-function writeStats(spreadsheetData, sheet, type, from, to) {
- var sortedExtractObjs, sortedMonths;
- var extractObjSums = [];
- var monthsSums = [];
- var result = {};
- var allMonths = {};
- var allExtractObjs = {};
- var months = Utils.getMonthsNames();
- var onlyCount = (type == 'event2');
- type = onlyCount ? 'event' : type;
+function writeStats(spreadsheetData, sheet, type, from, to, onlyCount) {
+ const months = Utils.getMonthsNames();
+ // stats = {
+ // "John": {
+ // "202009": {
+ // "duration": 5
+ // },
+ // "202210": {
+ // "duration": 105791
+ // }
+ // }
+ // }
+ const stats = {};
+ const foundMonths = {};
+ const foundNames = {};
spreadsheetData.forEach(function(item) {
- var extractObj, monthObj, identifier, month;
-
- if (item[type] && item.tariff) {
+ const clientOrEmployeeName = item[type];
- if (!result[item[type]]) {
- result[item[type]] = {};
- }
- extractObj = result[item[type]];
+ if (clientOrEmployeeName && item.tariff) {
+ const monthIdx = item.date.getMonth();
+ const month = monthIdx + 1;
+ const yearMonthID = item.date.getFullYear() + '' + (month < 10 ? '0' + month : month);
- month = item.date.getMonth() + 1;
- identifier = item.date.getFullYear() + '' + (month < 10 ? '0' + month : month);
+ foundMonths[yearMonthID] = months[monthIdx] + ' ' + item.date.getFullYear();
+ foundNames[clientOrEmployeeName] = true;
- allMonths[identifier] = months[month - 1] + ' ' + item.date.getFullYear();
- allExtractObjs[item[type]] = true;
-
- if (!extractObj[identifier]) {
- extractObj[identifier] = {
+ if (!stats[clientOrEmployeeName]) {
+ stats[clientOrEmployeeName] = {};
+ }
+ const dataForName = stats[clientOrEmployeeName];
+ if (!dataForName[yearMonthID]) {
+ dataForName[yearMonthID] = {
duration: onlyCount ? 1 : item.duration
};
} else {
- extractObj[identifier].duration += onlyCount ? 1 : item.duration;
+ dataForName[yearMonthID].duration += onlyCount ? 1 : item.duration;
}
}
});
- sortedExtractObjs = getSortedObjProps(allExtractObjs);
- sortedMonths = getSortedObjProps(allMonths);
+ const sortedFoundNames = getSortedObjProps(foundNames);
+ const sortedFoundMonths = getSortedObjProps(foundMonths);
- extractObjSums = Array.apply(null, new Array(sortedExtractObjs.length)).map(Number.prototype.valueOf, 0);
- monthsSums = Array.apply(null, new Array(sortedMonths.length)).map(Number.prototype.valueOf, 0);
+ const foundNamesSums = new Array(sortedFoundNames.length).fill(0);
+ const monthsSums = new Array(sortedFoundMonths.length).fill(0);
- for (var i = 0; i < sortedMonths.length; i++) {
- for (var j = 0; j < sortedExtractObjs.length; j++) {
- var ev = result[sortedExtractObjs[j]][sortedMonths[i]];
- var duration = 0;
+ // write stat for each name in each month and collect summaries
+ for (let i = 0; i < sortedFoundMonths.length; i++) {
+ const foundMonth = sortedFoundMonths[i];
+ for (let j = 0; j < sortedFoundNames.length; j++) {
+ const foundName = sortedFoundNames[j];
+ let statElement = stats[foundName][foundMonth];
+ let duration = 0;
- if (ev) {
- duration = ev.duration;
- extractObjSums[j] += duration;
+ if (statElement) {
+ duration = statElement.duration;
+ foundNamesSums[j] += duration;
monthsSums[i] += duration;
}
writeToCellSpec(sheet, j + 2, i + 2, {
@@ -96,30 +108,32 @@ function writeStats(spreadsheetData, sheet, type, from, to) {
}
}
- for (var i = 0; i < sortedExtractObjs.length; i++) {
+ // write names and summaries
+ for (let i = 0; i < sortedFoundNames.length; i++) {
writeToCellSpec(sheet, i + 2, 1, {
- value: sortedExtractObjs[i],
+ value: sortedFoundNames[i],
color: '#FFF2CC'
});
writeToCellSpec(sheet, i + 2, monthsSums.length + 2, {
- value: extractObjSums[i],
+ value: foundNamesSums[i],
isDuration: !onlyCount,
color: '#E2F3FF'
});
}
- for (var i = 0; i < sortedMonths.length; i++) {
+ // write months header and summaries
+ for (let i = 0; i < sortedFoundMonths.length; i++) {
writeToCellSpec(sheet, 1, i + 2, {
- value: allMonths[sortedMonths[i]],
+ value: foundMonths[sortedFoundMonths[i]],
color: '#FFF2CC'
});
- writeToCellSpec(sheet, sortedExtractObjs.length + 2, i + 2, {
+ writeToCellSpec(sheet, sortedFoundNames.length + 2, i + 2, {
value: monthsSums[i],
isDuration: !onlyCount,
color: '#E2F3FF'
});
}
- writeToCell(sheet, sortedExtractObjs.length + 8, 1, '* Statistika v časovém období: ' + Utils.getFormatedDate(from, true) + ' - ' + Utils.getFormatedDate(
+ writeToCell(sheet, sortedFoundNames.length + 8, 1, '* Statistika v časovém období: ' + Utils.getFormatedDate(from, true) + ' - ' + Utils.getFormatedDate(
to, true));
}
@@ -132,9 +146,9 @@ function writeStats(spreadsheetData, sheet, type, from, to) {
* @param obj obj with input data and its format (as {value: xx, color: xx, isDuration: xx, roundPrice: xx, oneDigitFormat: xx, twoDigitFormat: xx})
*/
function writeToCellSpec(sheet, row, col, obj) {
- var cell = sheet.getRange(row, col);
- var value = obj.value;
- var color = obj.color;
+ const cell = sheet.getRange(row, col);
+ let value = obj.value;
+ const color = obj.color;
if (obj.isDuration === true) {
cell.setNumberFormat('[h]:mm:ss');
diff --git a/src/Statistics/appsscript.json b/src/Statistics/appsscript.json
index cef8503..73b7786 100644
--- a/src/Statistics/appsscript.json
+++ b/src/Statistics/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 66
+ "version": 70
}
]
},
diff --git a/src/TableScript/appsscript.json b/src/TableScript/appsscript.json
index cef8503..73b7786 100644
--- a/src/TableScript/appsscript.json
+++ b/src/TableScript/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 66
+ "version": 70
}
]
},
diff --git a/src/Update/appsscript.json b/src/Update/appsscript.json
index cef8503..73b7786 100644
--- a/src/Update/appsscript.json
+++ b/src/Update/appsscript.json
@@ -5,7 +5,7 @@
{
"userSymbol": "Utils",
"libraryId": "1WquYtBor0ObwHMo1oIhKnCgboR5zBx2wjh5Hu-rbb0oSA5cY0d2PM6dZ",
- "version": 66
+ "version": 70
}
]
},
diff --git a/src/Utils/Date.js b/src/Utils/Date.js
index 614c10b..b9379ba 100644
--- a/src/Utils/Date.js
+++ b/src/Utils/Date.js
@@ -62,14 +62,14 @@ function getMonday(day) {
var retDay = new Date(day);
var weekday = day.getDay();
- if (weekday != 1) {
- if (weekday == 0) {
+ if (weekday !== 1) { // not monday
+ if (weekday === 0) { // sunday
retDay.setDate(day.getDate() - 6);
} else {
retDay.setDate(day.getDate() - weekday + 1);
}
}
- retDay.setHours(0, 0, 0);
+ retDay.setHours(0, 0, 0, 0);
return retDay;
}
@@ -82,7 +82,7 @@ function getMonday(day) {
function getNextMonday(monday) {
var retDay = new Date(monday);
retDay.setDate(monday.getDate() + 7);
- retDay.setHours(0, 0, 0);
+ retDay.setHours(0, 0, 0, 0);
return retDay;
}
@@ -95,7 +95,7 @@ function getNextMonday(monday) {
function getThisWeeksSunday(monday) {
var retDay = new Date(monday);
retDay.setDate(monday.getDate() + 6);
- retDay.setHours(0, 0, 0);
+ retDay.setHours(0, 0, 0, 0);
return retDay;
}
@@ -172,18 +172,16 @@ function getNumberOfWeeksInYear_(year) {
* @return true if weekToCompare in yearToCompare is in interval
*/
function isWeekWithinDates(from, to, yearToCompare, weekToCompare){
- // TODO: refactor to use weekStarts property
-
var fromWeek = getWeekNumber(from);
var fromYear = getWeeksYear(from);
var toWeek = getWeekNumber(to);
var toYear = getWeeksYear(to);
- if (yearToCompare < fromYear || (yearToCompare == fromYear && weekToCompare < fromWeek)) { // before
+ if (yearToCompare < fromYear || (yearToCompare === fromYear && weekToCompare < fromWeek)) { // before
return false;
}
- if (toYear < yearToCompare || (yearToCompare == toYear && toWeek < weekToCompare)) { // after
+ if (toYear < yearToCompare || (yearToCompare === toYear && toWeek < weekToCompare)) { // after
return false;
}
return true;
diff --git a/src/Utils/SpreadSheet.js b/src/Utils/SpreadSheet.js
index 6a7af27..0c24b8f 100644
--- a/src/Utils/SpreadSheet.js
+++ b/src/Utils/SpreadSheet.js
@@ -29,7 +29,7 @@ function createSpreadsheet(obj) {
moveFile_(file, obj.type, obj.year, obj.week);
}
- if (obj.type == 'Rozpis') {
+ if (obj.type === 'Rozpis') {
createFile(obj);
}
@@ -43,101 +43,53 @@ function createSpreadsheet(obj) {
* @param to to which date extract data
* @return {Array