class ProjectReport extends Report { get name() { return "Projects"; } get fieldInformation() { return { period_id: { hidden: true }, date: { displayName: "Date", type: "date", aggregationLabel: "Total" }, full_name: { displayName: "Employee" }, id_invoice: { displayName: "Invoiced?", type: "boolean" }, work: { displayName: "Work" }, notes: { displayName: "Notes" }, tariff: { displayName: "Tariff", type: "currency" }, duration: { displayName: "Work Hours", type: "number", aggregation: "sum", round: 4 }, total_value: { displayName: "Total Value", type: "currency", aggregation: "sum" } }; } get filterParameters() { return [ { from_date: { type: "date", default: Time.getLastMonthStartDate(), label: "From" }, to_date: { type: "date", default: Time.getLastMonthEndDate(), label: "to" } }, { invoiced: { type: "select", default: "all", label: "Show", values: { all: "all", invoiced_only: "invoiced only", not_invoiced_only: "not yet invoiced only" } } } ]; } get requestPath() { return "Reports/Project"; } buildTitleCell(fieldName, fieldInformation, cell) { super.buildTitleCell(fieldName, fieldInformation, cell); if (fieldName == "id_invoice") { cell.innerHTML += "
"; this.allInvoicedCheckbox = document.createElement("input"); this.allInvoicedCheckbox.type = "checkbox"; this.allInvoicedCheckbox.addEventListener("change", this.onMarkAllAsInvoicedCheckboxChanged.bind(this)); cell.appendChild(this.allInvoicedCheckbox); this.updateAllInvoicedCheckbox(); } } buildCell(fieldName, value, fieldInformation, cell, index) { super.buildCell(fieldName, value, fieldInformation, cell, index); //Create the checkbox list if it does not yet exist. if (!this.invoicedCheckboxes) { this.invoicedCheckboxes = { }; //Also use this opportunity to register the period change listener. TimeCards.dataManager.putDataListener("period", null, this.onPeriodUpdate.bind(this)); } if (fieldName == "id_invoice") { cell.innerHTML = ""; var periodId = this.data[index][0]; var idInvoice = this.data[index][3]; var invoicedCheckbox = document.createElement("input"); invoicedCheckbox.type = "checkbox"; invoicedCheckbox.setAttribute("period-id", periodId); invoicedCheckbox.checked = idInvoice !== null; invoicedCheckbox.className = "invoiced-checkbox"; invoicedCheckbox.addEventListener("change", this.onMarkAsInvoicedCheckboxChanged.bind(this)); cell.appendChild(invoicedCheckbox); this.invoicedCheckboxes[periodId] = invoicedCheckbox; } } buildCSVCell(fieldName, value, fieldInformation, index) { if (fieldName == "id_invoice") { var idInvoice = this.data[index][3]; return idInvoice !== null ? "✓" : "✗"; } return super.buildCSVCell(fieldName, value, fieldInformation, index); } onMarkAllAsInvoicedCheckboxChanged(event) { //Do nothing if there is no data. if (this.data.length <= 1) { return; } for (var i = 1; i < this.data.length; i++) { this.updatePeriodInvoiced(this.data[i][0], event.currentTarget.checked); } } onMarkAsInvoicedCheckboxChanged(event) { var periodId = event.currentTarget.getAttribute("period-id"); this.allInvoicedCheckbox.disabled = true; this.updatePeriodInvoiced(periodId, event.currentTarget.checked); } updatePeriodInvoiced(periodId, invoiced) { var period = TimeCards.dataManager.getEntity("period", periodId); if (period.id_invoice > 0) { console.warn("Ignoring the checkbox change because the period has an actual invoice assigned to it (invoice#" + period.id_invoice + ")."); return; } var idInvoice = invoiced ? -1 : null; var periodData = { id_invoice: idInvoice }; TimeCards.dataManager.store("period", periodId, periodData); } updateAllInvoicedCheckbox() { //Iterate over all rows and decide about the checked or indeterminate state of the check all checkbox. var checkedCount = 0; for (var i = 1; i < this.data.length; i++) { if (this.data[i][3] !== null) { checkedCount++; } } this.allInvoicedCheckbox.indeterminate = checkedCount > 0 && checkedCount < this.data.length - 1; this.allInvoicedCheckbox.checked = this.data.length > 1 && checkedCount == this.data.length - 1; this.allInvoicedCheckbox.disabled = false; } /** * This event is listened to update the checkbox after a period was marked as invoiced. */ onPeriodUpdate(periodId, period) { //Inform the user if one of the loaded periods is deleted. if (!period) { if (periodId in this.invoicedCheckboxes) { //alert("One of the periods in this report has just been deleted. Please reload the report to make sure that it's up to date."); //TODO: Localize this. } return; } //Update the corresponding invoiced checkbox if one is present. if (periodId in this.invoicedCheckboxes) { this.invoicedCheckboxes[periodId].checked = period.id_invoice !== null; //Also update the period in the local report data. for (var i = 1; i < this.data.length; i++) { if (this.data[i][0] == periodId) { this.data[i][3] = period.id_invoice; } } //Also update the checkbox in the header. this.updateAllInvoicedCheckbox(); } } }