【Publisher】Let's create a hybrid report

# Introduction #
This time, I will introduce the advanced edition of the WEB report.
We will use the standard prompts and table sections of Sharperlight and add custom elements to them.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/2af28118-4f21-61ae-ecc7-08455313aa44.png)
The data filtered through the prompts will be displayed, creating an interactive web report where users can take actions on the displayed data. In this example, two buttons, `Approve` and `Reject`, are provided. JavaScript will be used to write the logic so that when each button is pressed, the corresponding processing is performed.

# Creating a WEB Report #
Launch the **Publisher** from the Sharperlight application menu.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/5c458131-53ca-2bb5-0bb6-fd258d27b43a.png)
Begin creating a new web report by clicking the `New` button.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/fb16e8c0-b719-cdaf-13c7-d02bbfbbf00a.png)
In the **General** tab, fill in the `Unique Code` (Group + Code), `Title`, and `Report Title`.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/63d28d24-5190-579c-8649-1a4d13efa6ba.png)
Define the query by clicking the `Edit Query` button at the bottom of the dialog.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/171a12dd-4755-4e8c-a06d-6c4546770787.png)
The Query Builder will open. I tried creating a query using the SAP Business One data model as shown in the figure below.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/190e869b-3f69-2f8c-e0bb-a1f4f153db24.png)

1. **Document Draft Number**: This filter will be displayed as a prompt
2. **CurrentUser**: Since you want to use this in JavaScript, define it as a prompt filter (it won't form part of the query's WHERE clause, but can prompt the user for input). Additionally, set it to Hidden if you don't want it to be displayed as a prompt
3. Elements constituting the table

Verify the query's functionality by using the `Preview` button. It worked well.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/41df834d-6aa9-cc4a-0ebd-e93fbba85a74.png)
Save the query by clicking the `OK` button, and then save the web report using the `OK` button as well.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/5782d916-4c54-d96a-2bd1-9750f3111bfb.png)


# Creating Custom HTML + JavaScript Code #
Let's proceed with creating this section.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/ac6f815e-39fe-ccdf-e85a-a7dfb9a8e0e0.png)
Created with HTML + JavaScript. Write with an editor such as Visual Studio Code.
The two buttons and the text area are defined like this.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/80b9c96f-ad28-8480-ed2b-3b96d997f175.png)
The processing when the button is pressed is like this.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/1fa3aded-99a1-3561-bc5b-c73a690f7b3e.png)
1. This part receives filter information from the query of the embedded web report (previously created web report). `@Company`, `@DocumentDraftNumber` are reference codes for the names of filters in the query
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/b06071f7-3be2-0f8c-5c49-ee7647a2a68a.png)
2. This part sends a query to the Sharperlight RESTful service and receives a dataset. This code is used when buttons like `Approve` or `Reject` are pressed. It retrieves the same data currently displayed, plus additional information using a Sharperlight query. The retrieved data is then passed to the next processing step. For example, this code could be utilized to write back the data to another table using Sharperlight's Writeback feature. In this case, the retrieved data is only displayed on the screen.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/201ae502-11e0-0bf0-bb31-b1b6868d5ecc.png)
3. The URL request syntax for sending a query to the Sharperlight RESTful service in the step 2 
 is defined. This query (web report) has to be defined in the Publisher as well.

 I will put all the code here.
 ```
 <script>
    var gPublisherGroup = "QiitaSample";
    var gStatus = '';
    var gFilterCompany = "{*Filter[@Company]}".replace(/'/g, "\\'");
    var gFilterDocumentDraftNumber = '{*Filter[@DocumentDraftNumber]}'.replace(/'/g, "\\'");
    var gDatasetLinesURL = '{*Url.Root}DataSource/?query=' + gPublisherGroup + '.Hybrid_ds_Lines' 
                    + '&fltCompany={@@COMPANY}&fltDocumentDraftNumber={@@DOCUMENTDRAFTNUMBER}'
                    + '&dfmt=jsonarray&dcat=UseNames&usid={_System.Rest.Usid}';
    
    // Callback function sets
    var getCallback = {
        success: getRequest_Success,
        failure: getRequest_fail
    };

    
    //===================================
    // Global Variabales
    //===================================
    var gDatasetLines = [];
    var gHead_Comment = "";
    var gLine_Buffer = [];

    function btApprove_click(source, mode){
        try{
            gStatus = mode;
        
            // Keep input value
            gHead_Comment = $.trim($('textarea#ApprovalComment').val());
            
            //====================================================
            // Get approved documents detail
            //====================================================
            var dsUrl = gDatasetLinesURL.replace("{@@COMPANY}", gFilterCompany).replace("{@@DOCUMENTDRAFTNUMBER}",gFilterDocumentDraftNumber);
            console.log(dsUrl);
            Sharperlight_Get(dsUrl, getCallback, "A");
        
        }catch (err){
            console.error('Error on btSubmitAll_click(): ' + err.message);
        }
    }

    function btReject_click(source, mode){
        try{
            gStatus = mode;

            // Keep input value
            gHead_Comment = $.trim($('textarea#ApprovalComment').val());
            
            //====================================================
            // Get approved documents detail
            //====================================================
            var dsUrl = gDatasetLinesURL.replace("{@@COMPANY}", gFilterCompany).replace("{@@DOCUMENTDRAFTNUMBER}",gFilterDocumentDraftNumber);
            console.log(dsUrl);
            Sharperlight_Get(dsUrl, getCallback, "R");
        
        } catch (err){
            console.error('Error on btReject_click(): ' + err.message);
        }
    }


    //====================================================
    // Request datasets
    //====================================================
    var gPostingStatus = "X";
    function Sharperlight_Get(url, cb, status){
        try {
            if (url != ""){
                gPostingStatus = status;
                var request = YAHOO.util.Connect.asyncRequest('GET', url, cb);
            }
        } catch (err) {
            console.error('Sharperlight_Get(): ' + err.message);
        }
    };
    
    // callback functions for header request
    function getRequest_Success(o) {
        console.log("getRequest_Success: " + o.responseText);
        gDatasetLines = JSON.parse(o.responseText);
        
        if (gPostingStatus == "A"){
            if (!confirm('Are you sure you would like to approve all the document(s)?')){
                return;
            }
        }else if(gPostingStatus == "R"){
            if (!confirm('Are you sure you would like to reject all the document(s)?')){
                return;
            }
        }else{
            alert("Posting Status was wrong.");
            return;
        }
        
        if (gDatasetLines.length == 0) { 
            console.log('No document records found or the data already was processed');
            window.parent.location.reload();
            return; 
        }
            
        gLine_Buffer = [];
        for(var r=0; r<gDatasetLines.length; r++){
                var rowItem = {
                    'CompanyBase': gFilterCompany,
                    'InternalNumber': gDatasetLines[r].InternalNumber,
                    'DocumentDraftNumber': gFilterDocumentDraftNumber,
                    'Answer': gPostingStatus,
                    'Authorizer': gDatasetLines[r].Authorizer,
                    'Date': gDatasetLines[r].Date,
                    'Comment': gHead_Comment
                    }
            gLine_Buffer.push(rowItem);        
        }
        
        // Post Remarks to the server
        var message = "";
        if (gLine_Buffer.length > 0){
            for (var l=0; l<gLine_Buffer.length; l++){
                message +="CompanyBase: " +  gLine_Buffer[l].CompanyBase + "</br>InternalNumber: " + gLine_Buffer[l].InternalNumber + "</br>DocumentDraftNumber: " + gLine_Buffer[l].DocumentDraftNumber + "</br>Answer: " + gLine_Buffer[l].Answer + "</br>Authorizer: " + gLine_Buffer[l].Authorizer + "</br>Date: " + gLine_Buffer[l].Date + "</br>Comment: " + gLine_Buffer[l].Comment + (l<gLine_Buffer.length ? "</br></br>" : "");
            }
            kendo.alert(message);
        }
    
    };
    
    function getRequest_fail(o){
        console.error("getRequest_fail: " + o.responseText);
    };

</script>

<table style="width:100%">
    <tr>
        <td style="width:110px;">
            <button id='btApprove' class="button button1" onClick='btApprove_click(this.id, "A")'>Approve</button>
            <button id='btReject' class="button button2" onClick='btReject_click(this.id, "R")'>Reject</button>
        </td>
    </tr>
    <tr>
        <td colspan="2"><textarea id="ApprovalComment" maxlength="1000"></textarea></td>
    </tr>
</table>


<div id="PostMessage" style="display: none">The post result message will be shown here.</div>


<script type="text/javascript">
    
    $(document).ready(function() {
        console.log("Page is ready");
    });

</script>
 ```

 
# Embedding HTML + JavaScript Code #
Save the earlier HTML + JavaScript code as an HTML file.
Open the definition of the previously created web report.
Navigate to the **Options** tab and click the `Edit` button under **Resources**.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/20d23432-6948-866f-ead3-c369c35c624d.png)
In the resource dialog, initiate the definition of a new resource by clicking on the `New` icon.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/a6a8c5ac-1a39-eebe-b485-8021fa208be0.png)
Next, use the file search icon for the path to specify the HTML file created earlier.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/ea548ac8-051b-5996-ab20-c6d7cf753902.png)

Once the file is specified, use the `Copy` button under **Reference** to copy the unique code to the clipboard.
Close the resource dialog.
Notice that the `Edit` button for resources has turned green. This means that the HTML file has now been attached as a resource.
Check the `Header` checkbox under **Custom Styles**, and click the `Edit` button.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/b8e8b7bb-4fd3-5a4c-7710-e7b49519ec57.png)

Proceed by selecting `No`.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/eb3bee77-5ca7-d70f-5ca3-26b8711d3d27.png)

The Custom HTML header dialog will open.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/a8196681-f3c6-94af-e055-96bf3edba845.png)

Keep only the **ReportContentSectionBegin** and **ReportContentSectionEnd** tags, and remove the others.
```
<!--ReportContentSectionBegin-->
<!--ReportContentSectionEnd-->
```
Paste the reference code of the embedded resource file copied to the clipboard earlier between the Begin and End tags.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/2fdecc82-eb02-1bd1-d989-12fce66ba1fa.png)

Save by clicking the `OK` button. The embedding is now complete. The `Edit` button for the header has also turned green. Save the changes by clicking the `Apply` button.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/200c607e-765d-10fa-0a58-50ef12de17dc.png)

# Definition of Classes #
Define the CSS used in the previously created HTML + JavaScript code for this web report.
In the **Options** tab, under **Custom Styles** settings, check the `CSS` checkbox, and click the `Edit` button.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/53c592ff-fb1a-3c38-5394-4c82e0ef060d.png)
Paste the code below.
```
<style type="text/css">
	body{
		font-family: Monospace;
		font-size: 17px;
	}
	.button {
		margin-bottom: 15px;	
		margin-left: 20px;	
		display: inline-block;
		padding: 8px 25px;
		font-size: 15px;
		cursor: pointer;
		text-align: center;
		text-decoration: none;
		outline: none;
		color: #fff;
		border: none;
		border-radius: 7px;
		box-shadow: 0 6px #999;
	}
	.button1{
		background-color: #2F8272;
		width:	105px;
	}
	.button1:hover {
		background-color: #225e52;
	}
	.button1:active {
		background-color: #225e52;
		box-shadow: 0 5px #666;
		transform: translateY(4px);
	}
	
	.button2{
		background-color: #ED4C32;
		width:	105px;
	}
	.button2:hover {
		background-color: #bc2710;
	}
	.button2:active {
		background-color: #bc2710;
		box-shadow: 0 5px #666;
		transform: translateY(4px);
	}

	textarea {
		width: 650px;
  		height: 75px;
  		padding: 8px 8px;
  		box-sizing: border-box;
  		border: 2px solid #ccc;
  		border-radius: 4px;
  		background-color: #f8f8f8;
  		font-size: 16px;
  		resize: vertical;
	}
	#PostMessage{
		position: relative;
    		top: -6px;
    		margin-left: -40px;
	}
	.reviewedByLabel{
		display: inline-block;
    		margin-left: 15px;
    		position: relative;
    		top: -6px;
	}
	.reviewedBy{
		display: inline-block;
    		position: relative;
    		top: -6px;
		width: 200px;
	}
	.inspactor{
		width: 200px;
		height: 25px;
	}
	.inspactorValidationError{
		background-color: #eb8584;
	}
	.originalTotalLabel{
		display: inline-block;
    		margin-left: 15px;
    		position: relative;
    		top: -6px;
	}
	.originalTotal{
		display: inline-block;
    		position: relative;
    		top: -6px;
	}
	.newTotalLabel{
		display: inline-block;
    		margin-left: 15px;
    		position: relative;
    		top: -6px;
	}
	.newTotal{
		display: inline-block;
    		position: relative;
    		top: -6px;
	}
	#dash1Z{
		position: absolute;
		left: 888px;
	}
</style>
```
It is like this.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/3f302b78-fb7b-2e07-c8ec-da9fa6270ce2.png)
Save with the `OK` button. The `Edit` button in CSS has also turned green. Save the changes with the `Apply` button.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/b3c71dfa-3ce2-98c9-d22c-ab4404f2e2c8.png)


# Theme Settings #
Let's enhance the appearance of the table.
Go to the **Options** tab, check the `Theme` checkbox under **Custom Styles**, and press the `Edit` button.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/d51cccf2-68c5-5f64-7368-09de52aabe22.png)

Paste the following code into the URL parameter text box in the opened theme dialog.
```
&style=tmp2
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/cfcb01c1-a76a-f0bd-4b92-202d020db165.png)

Save the settings with the `OK` button. The `Edit` button in the theme has also turned green. Save the changes with the `Apply` button. Furthermore, close the definition of the Web Report with the `OK` button.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/af4a2a0e-2864-578c-2c0f-39d7fdea9cfc.png)

The creation of the Hybrid Web Report is now complete.


# Verification of Operation #
Now, let's proceed with the verification. Start the Sharperlight service from the Windows service or Sharperlight application menu. Select the Web Report you created earlier from the Publisher's report list, and choose `View Report` from the right-click menu.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/f7b9888c-99d4-2792-126e-dcd1be850016.png)

The Web Report will open in your browser. Leave the `Document Draft Number` filter blank and execute the query by clicking the `Submit` button.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/7c1a2da8-1fa0-b636-131d-7e093056ab87.png)

The table will be displayed along with the HTML + JavaScript components.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/83163809-9e2f-8368-648f-b1ab66aaf411.png)

If you press the `Approve` button, a confirmation message will appear. Press `OK`, and if the next information is displayed, everything is functioning correctly.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/8328b2a1-9311-d18f-2be5-070c26852d2b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530698/166f576c-f2c4-d7a6-a833-dc2d485f5a4a.png)


# Afterword #
By entrusting the data access part to Sharperlight, we can focus on other aspects, can't we?