001/**
002 * Copyright 2004-2015 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.hr.lm.leaveCalendar;
017
018import com.gargoylesoftware.htmlunit.html.HtmlButtonInput;
019import com.gargoylesoftware.htmlunit.html.HtmlElement;
020import com.gargoylesoftware.htmlunit.html.HtmlForm;
021import com.gargoylesoftware.htmlunit.html.HtmlPage;
022import org.apache.commons.lang.StringUtils;
023import org.joda.time.DateTime;
024import org.json.simple.JSONArray;
025import org.json.simple.JSONObject;
026import org.json.simple.JSONValue;
027import org.junit.Assert;
028import org.junit.Ignore;
029import org.junit.Test;
030import org.kuali.hr.TestAutoLoginFilter;
031import org.kuali.hr.util.HtmlUnitUtil;
032import org.kuali.kpme.core.FunctionalTest;
033import org.kuali.kpme.core.api.assignment.Assignment;
034import org.kuali.kpme.core.api.assignment.AssignmentDescriptionKey;
035import org.kuali.kpme.core.api.calendar.entry.CalendarEntry;
036import org.kuali.kpme.core.api.earncode.EarnCode;
037import org.kuali.kpme.core.calendar.entry.CalendarEntryBo;
038import org.kuali.kpme.core.service.HrServiceLocator;
039import org.kuali.kpme.core.util.HrContext;
040import org.kuali.kpme.core.util.TKUtils;
041import org.kuali.kpme.tklm.leave.calendar.LeaveCalendarDocument;
042import org.kuali.kpme.tklm.leave.calendar.web.LeaveCalendarWSForm;
043import org.kuali.kpme.tklm.leave.service.LmServiceLocator;
044
045import java.util.ArrayList;
046import java.util.HashMap;
047import java.util.List;
048import java.util.Map;
049
050import static org.junit.Assert.assertTrue;
051
052@FunctionalTest
053public class LeaveCalendarWorkflowIntegrationTest extends LeaveCalendarWebTestBase {
054
055    public static final String USER_PRINCIPAL_ID = "admin";
056        private DateTime JAN_AS_OF_DATE = new DateTime(2010, 1, 1, 0, 0, 0, 0, TKUtils.getSystemDateTimeZone());
057
058        @Ignore
059    @Test
060    /**
061     * - create timesheet
062     * - add two 8 hour time blocks
063     * - submit timesheet for routing
064     * - ## login as approver
065     * - look for approval button
066     * - approve timeblock
067     * - verify approval button gone
068     * - ## login as original user
069     * - verify submit for routing button gone
070     */
071    public void testLeaveCalendarSubmissionIntegration() throws Exception {
072        DateTime asOfDate = new DateTime(2011, 3, 1, 12, 0, 0, 0, TKUtils.getSystemDateTimeZone());
073        CalendarEntry pcd =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDatesForLeaveCalendar(USER_PRINCIPAL_ID, asOfDate);
074        Assert.assertNotNull("No CalendarEntry", pcd);
075        LeaveCalendarDocument tdoc = LmServiceLocator.getLeaveCalendarService().openLeaveCalendarDocument(USER_PRINCIPAL_ID, pcd);
076        String tdocId = tdoc.getDocumentId();
077        HtmlPage page = loginAndGetLeaveCalendarHtmlPage("admin", tdocId, true);
078
079        // 1. Obtain User Data
080        Assignment assignment = HrServiceLocator.getAssignmentService().getAssignment(HrContext.getPrincipalId(), AssignmentDescriptionKey.get("IU-BL_30_30_30"), JAN_AS_OF_DATE.toLocalDate());
081        EarnCode earnCode = HrServiceLocator.getEarnCodeService().getEarnCode("VAC", JAN_AS_OF_DATE.toLocalDate());
082
083        // 2. Set Timeblock Start and End time
084        // 3/02/2011 - 8:00a to 4:00pm
085        DateTime start = new DateTime(2011, 3, 2, 8, 0, 0, 0, TKUtils.getSystemDateTimeZone());
086        DateTime end = new DateTime(2011, 3, 2, 16, 0, 0, 0, TKUtils.getSystemDateTimeZone());
087
088        HtmlForm form = page.getFormByName("LeaveCalendarForm");
089        Assert.assertNotNull(form);
090
091        // Build an action form - we're using it as a POJO, it ties into the
092        // existing TK validation setup
093        LeaveCalendarWSForm tdaf = LeaveCalendarTestUtils.buildLeaveCalendarForm(tdoc, assignment, earnCode, start, end, null, true);
094        LeaveCalendarTestUtils.setTimeBlockFormDetails(form, tdaf);
095        page = LeaveCalendarTestUtils.submitLeaveCalendar(getWebClient(), getLeaveCalendarUrl(tdocId), tdaf);
096        Assert.assertNotNull(page);
097        HtmlUnitUtil.createTempFile(page, "LeaveBlockPresent");
098
099        // Verify block present on rendered page.
100        String pageAsText = page.asText();
101
102        // JSON
103        //
104        //
105        // Grab the leaveBlock data from the text area. We can check specifics there
106        // to be more fine grained in our validation.
107        String dataText = page.getElementById("leaveBlockString").getFirstChild().getNodeValue();
108        JSONArray jsonData = (JSONArray)JSONValue.parse(dataText);
109        final JSONObject jsonDataObject = (JSONObject) jsonData.get(0);
110        Assert.assertTrue("leaveBlock Data Missing.", checkJSONValues(new JSONObject() {{ put("outer", jsonDataObject); }},
111                new ArrayList<Map<String, Object>>() {{
112                    add(new HashMap<String, Object>() {{
113                        put("earnCode", "VAC");
114                        put("leaveAmount", "-8");
115                        put("earnCode", "VAC");
116                        put("leaveDate", "03/02/2011");
117                        //put("endNoTz", "2011-03-02T16:00:00");
118                        put("title", "SDR1 Work Area");
119                        put("assignment", "IU-BL_30_30_30");
120                    }});
121                }},
122                new HashMap<String, Object>() {{  }}
123        ));
124
125        // Check the Display Rendered Text for Time Block, Quick Check
126        Assert.assertTrue("TimeBlock not Present.", pageAsText.contains("SDR1 Work Area-SDR1 task"));
127        Assert.assertTrue("TimeBlock not Present.", pageAsText.contains("VAC (-8)"));
128
129        //
130        // Route Timesheet
131        //
132        // Routing is initiated via javascript, we need to extract the routing
133        // action from the button element to perform this action.
134        HtmlButtonInput routeButton = (HtmlButtonInput)page.getElementById("ts-route-button");
135        String routeHref = HtmlUnitUtil.getOnClickHref(routeButton);
136        // The 'only' way to do the button click.
137        page = HtmlUnitUtil.gotoPageAndLogin(getWebClient(), getBaseURL() + "/" + routeHref);
138        //HtmlUnitUtil.createTempFile(page, "RouteClicked");
139        pageAsText = page.asText();
140        // Verify Route Status via UI
141        Assert.assertTrue("Wrong Document Loaded.", pageAsText.contains(tdocId));
142        Assert.assertTrue("Document not routed.", pageAsText.contains("Enroute"));
143        routeButton = (HtmlButtonInput)page.getElementById("ts-route-button");
144        Assert.assertNull("Route button should not be present.", routeButton);
145        HtmlElement approveButton = (HtmlButtonInput)page.getElementById("ts-approve-button");
146        Assert.assertNull("Approval button should not be present.", approveButton);
147
148        //
149        // Login as Approver, who is not 'admin'
150        page = loginAndGetLeaveCalendarHtmlPage("eric", tdocId, true);
151        //HtmlUnitUtil.createTempFile(page, "2ndLogin");
152        pageAsText = page.asText();
153        Assert.assertTrue("Document not routed.", pageAsText.contains("Enroute"));
154        approveButton = (HtmlButtonInput)page.getElementById("ts-approve-button");
155        Assert.assertNotNull("No approval button present.", approveButton);
156
157        // Click Approve
158        // And Verify
159        //
160        routeHref = HtmlUnitUtil.getOnClickHref(approveButton);
161        TestAutoLoginFilter.OVERRIDE_ID = "eric";
162        page = HtmlUnitUtil.gotoPageAndLogin(getWebClient(), getBaseURL() + "/" + routeHref);
163        TestAutoLoginFilter.OVERRIDE_ID = "";
164        //HtmlUnitUtil.createTempFile(page, "ApproveClicked");
165        pageAsText = page.asText();
166        Assert.assertTrue("Wrong Document Loaded.", pageAsText.contains(tdocId));
167        Assert.assertTrue("Login info not present.", pageAsText.contains("Employee Id:"));
168        Assert.assertTrue("Login info not present.", pageAsText.contains("eric, eric"));
169        Assert.assertTrue("Document not routed.", pageAsText.contains("Final"));
170        approveButton = (HtmlElement)page.getElementById("ts-approve-button");
171        Assert.assertNull("Approval button should not be present.", approveButton);
172    }
173    
174        @Ignore
175    @Test
176    public void testRedirectionForBalanceTransferOnLeaveApprove() throws Exception {
177                //Create a leave summary with a single row containing an accrual category that has exceeded max balance limit.
178/*              LeaveSummary ls = new LeaveSummary();
179                List<LeaveSummaryRow> leaveSummaryRows = new ArrayList<LeaveSummaryRow>();
180                //A leave summary row for an accrual category over max balance.
181                LeaveSummaryRow lsr = new LeaveSummaryRow();
182                lsr.setAccrualCategory("debitAC1");
183                lsr.setAccrualCategoryId("10055");
184                lsr.setAccrualCategoryRuleId("3000");
185                lsr.setLeaveBalance(new BigDecimal(500));
186                //debitAC1 accrual category has a max balance of 100.
187                leaveSummaryRows.add(lsr);
188                //A leave summary row for an accrual category to accept transfers.
189                lsr = new LeaveSummaryRow();
190                lsr.setAccrualCategory("creditAC1");
191                lsr.setAccrualCategoryId("10056");
192                lsr.setAccrualCategoryRuleId("3001");
193                lsr.setLeaveBalance(BigDecimal.ZERO);
194                
195                leaveSummaryRows.add(lsr);
196                ls.setLeaveSummaryRows(leaveSummaryRows);
197        setBaseDetailURL(TkTestConstants.Urls.LEAVE_CALENDAR_SUBMIT_URL + "?documentId=");
198        Date asOfDate = new Date((new DateTime(2011, 3, 1, 12, 0, 0, 0, TKUtils.getSystemDateTimeZone())).getMillis());
199        CalendarEntry pcd = HrServiceLocator.getCalendarService().getCurrentCalendarDatesForLeaveCalendar(USER_PRINCIPAL_ID, asOfDate);
200        Assert.assertNotNull("No CalendarEntry", pcd);
201        LeaveCalendarDocument tdoc = LmServiceLocator.getLeaveCalendarService().openLeaveCalendarDocument(USER_PRINCIPAL_ID, pcd);
202        String tdocId = tdoc.getDocumentId();
203
204        // Build an action form - we're using it as a POJO, it ties into the
205        // existing TK validation setup
206        LeaveCalendarWSForm tdaf = LeaveCalendarTestUtils.buildLeaveCalendarFormForSubmission(tdoc, ls);
207
208        HtmlPage page = LeaveCalendarTestUtils.submitLeaveCalendar2(getLeaveCalendarUrl(tdocId), tdaf);
209        Assert.assertNotNull(page);
210        HtmlUnitUtil.createTempFile(page, "LeaveBlockPresent");
211
212        // Verify block present on rendered page.
213        String pageAsText = page.asText();
214        System.out.print(pageAsText);
215                
216                */
217                //LeaveCalendarWSForm mockForm = LeaveCalendarTestUtils.buildLeaveCalendarForm(tdoc, assignment, earnCode, start, end, null, true);
218                //Attach leave summary to relevant object (leavecalendardocument?)
219                //load LeaveCalendarDocument into web container
220                //leave calendar document must have status "initiated"
221                //mock the submit action on behalf of the principal who owns the leave calendar.
222                //redirect should occur, which loads the balance transfer document.
223                //balance transfer document should have all fields locked except for transfer amount.
224                //mock transfer action on behalf of the principal.
225                //verify leave block creation
226                assertTrue("Dummy assertion 2", true);
227
228    }
229
230
231    /**
232     * Examines the JSON structure that is written to each output TimeDetails
233     * page.
234     * @param json The JSON Object to examine
235     * @param thdList The (optional) list of Time Hour Details values
236     * @param checkValues The list of values to check for in the JSON object
237     * @return true if the JSON object contains the required values, false otherwise.
238     */
239    public static boolean checkJSONValues(JSONObject json, List<Map<String,Object>> thdList, Map<String,Object> checkValues) {
240        boolean contains = false;
241
242        for(Object eso : json.entrySet()) {
243            // This is the outer TimeBlock ID -> Time Block Data mapping
244            Map.Entry e = (Map.Entry)eso;
245            JSONObject innerMap = (JSONObject)e.getValue(); // the values we actually care about.
246            boolean localContains = true;
247            for (Map.Entry<String,Object> cve : checkValues.entrySet()) {
248                Object joValue = innerMap.get(cve.getKey());
249                Object cvValue = cve.getValue();
250
251                // Null Checks..
252                if (cvValue == null && joValue == null)
253                    localContains &= true;
254                else if (joValue == null || cvValue == null)
255                    localContains = false;
256                else
257                    localContains &= StringUtils.equals(joValue.toString(), cvValue.toString());
258            }
259
260            contains |= localContains;
261        }
262
263        return contains;
264    }
265
266    public static boolean checkJSONValues(String json, List<Map<String,Object>> thdList, Map<String,Object> checkValues) {
267        return checkJSONValues((JSONObject)JSONValue.parse(json), thdList, checkValues);
268    }
269}