001    /**
002     * Copyright 2004-2013 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     */
016    package org.kuali.hr.time.util;
017    
018    import java.math.BigDecimal;
019    import java.net.URLEncoder;
020    import java.util.List;
021    
022    import com.gargoylesoftware.htmlunit.WebClient;
023    import org.apache.log4j.Logger;
024    import org.joda.time.DateTime;
025    import org.joda.time.Interval;
026    import org.kuali.hr.time.assignment.Assignment;
027    import org.kuali.hr.time.assignment.AssignmentDescriptionKey;
028    import org.kuali.hr.time.detail.validation.TimeDetailValidationUtil;
029    import org.kuali.hr.time.detail.web.TimeDetailActionFormBase;
030    import org.kuali.hr.time.earncode.EarnCode;
031    import org.kuali.hr.time.test.HtmlUnitUtil;
032    import org.kuali.hr.time.timesheet.TimesheetDocument;
033    
034    import com.gargoylesoftware.htmlunit.html.HtmlButton;
035    import com.gargoylesoftware.htmlunit.html.HtmlForm;
036    import com.gargoylesoftware.htmlunit.html.HtmlPage;
037    import org.kuali.hr.util.filter.TestAutoLoginFilter;
038    
039    public class TimeDetailTestUtils {
040    
041        private static final Logger LOG = Logger.getLogger(TimeDetailTestUtils.class);
042    
043        /**
044         * From the provided set of parameters, build an action form suitable for
045         * submitting to the TimeDetailAction servlet. In our case, we are mostly
046         * using it in a mock type of situation.
047         *
048         * @param timeshetDocument
049         * @param assignment
050         * @param earnCode
051         * @param start
052         * @param end
053         * @param amount
054         * @param acrossDays
055         * @param timeblockId
056         *
057         * @return A populated TimeDetailActionFormBase object.
058         */
059        public static TimeDetailActionFormBase buildDetailActionForm(TimesheetDocument timeshetDocument, Assignment assignment, EarnCode earnCode, DateTime start, DateTime end, BigDecimal amount, boolean acrossDays, String timeblockId, boolean spanningWeeks) {
060            TimeDetailActionFormBase tdaf = new TimeDetailActionFormBase();
061    
062            BigDecimal hours = null;
063            String startTimeS = null;
064            String endTimeS = null;
065            String startDateS;
066            String endDateS;
067            String selectedEarnCode;
068            String selectedAssignment;
069    
070            if (amount == null) {
071                if (start != null && end != null) {
072                    Interval se_i = new Interval(start, end);
073                    hours = TKUtils.convertMillisToHours(se_i.toDurationMillis());
074                }
075    
076                // the date/time format is defined in tk.calendar.js. For now, the format is 11/17/2010 8:0
077                startTimeS = start.toString("H:mm");
078                endTimeS = end.toString("H:mm");
079            }
080    
081            startDateS = start.toString("MM/dd/YYYY");
082            endDateS = end.toString("MM/dd/YYYY");
083    
084            AssignmentDescriptionKey adk = new AssignmentDescriptionKey(assignment);
085            selectedAssignment = adk.toAssignmentKeyString();
086    
087            selectedEarnCode = earnCode.getEarnCode();
088    
089            tdaf.setAcrossDays(acrossDays ? "y" : "n");
090            tdaf.setSpanningWeeks(spanningWeeks ? "y" : "n"); // KPME-1446
091            tdaf.setAmount(amount);
092            tdaf.setHours(hours);
093            tdaf.setStartTime(startTimeS);
094            tdaf.setEndTime(endTimeS);
095            tdaf.setStartDate(startDateS);
096            tdaf.setEndDate(endDateS);
097            tdaf.setTkTimeBlockId(timeblockId);
098            tdaf.setTimesheetDocument(timeshetDocument);
099            tdaf.setSelectedAssignment(selectedAssignment);
100            tdaf.setSelectedEarnCode(selectedEarnCode);
101            tdaf.setMethodToCall("addTimeBlock");
102    
103            return tdaf;
104        }
105    
106        /**
107         * Set the attributes on the provided html form to the values found in the provided
108         * ActionForm. Errors are returned in the List<String> object.
109         *
110         * @param form The HtmlForm to populate.
111         * @param tdaf The ActionForm with values we will use to populate.
112         *
113         * @return A list of string error messages from the validation call.
114         */
115        public static List<String> setTimeBlockFormDetails(HtmlForm form, TimeDetailActionFormBase tdaf) {
116            // Validation -- the same call the WS makes. (should already be valid...)
117            List<String> errors = TimeDetailValidationUtil.validateTimeEntryDetails(tdaf);
118    
119            // If validation passes, we can add the time block.
120            if (errors.size() == 0) {
121                if (tdaf.getTkTimeBlockId() != null) {
122                    form.setAttribute("tkTimeBlockId", tdaf.getTkTimeBlockId().toString());
123                }
124                form.setAttribute("startDate", tdaf.getStartDate());
125                form.setAttribute("endDate", tdaf.getEndDate());
126    
127                if (tdaf.getAmount() != null) {
128                    form.setAttribute("amount", tdaf.getAmount().toString());
129                } else {
130                    form.setAttribute("startTime", tdaf.getStartTime());
131                    form.setAttribute("endTime", tdaf.getEndTime());
132                    form.setAttribute("hours", tdaf.getHours().toString());
133                }
134    
135                form.setAttribute("selectedEarnCode", tdaf.getSelectedEarnCode());
136                form.setAttribute("selectedAssignment", tdaf.getSelectedAssignment());
137                form.setAttribute("acrossDays", tdaf.getAcrossDays());
138                form.setAttribute("methodToCall", tdaf.getMethodToCall());
139            }
140    
141            return errors;
142        }
143    
144        /**
145         * This is a 'hacker' method to get around the fact that in HtmlUnit you
146         * can no longer directly submit forms if there are no buttons. We
147         * simply add a button to the form, and click it!
148         *
149         * @param page The HtmlPage the form came from.
150         * @param form The HtmlForm you wish to submit.
151         * @return The return results from clicking .submit()
152         */
153        private static HtmlPage submitTimeDetailsDep(HtmlPage page, HtmlForm form) {
154            HtmlButton submitButton = null;
155    
156            //ScriptResult sr = page.executeJavaScript("document.forms[\"TimeDetailActionForm\"].submit();");
157    
158            if (submitButton == null) {
159                submitButton = (HtmlButton)page.createElement("button");
160                submitButton.setAttribute("type", "submit");
161                form.appendChild(submitButton);
162            }
163    
164            HtmlPage newPage = null;
165            try {
166                submitButton.click();
167            } catch (Exception e) {
168                LOG.error("While submitting time detail form", e);
169            }
170    
171            return newPage;
172        }
173    
174    
175        /**
176         * A method to wrap the submission of the time details.
177         * @param baseUrl
178         * @param tdaf
179         * @return
180         */
181        public static HtmlPage submitTimeDetails(WebClient webClient, String baseUrl, TimeDetailActionFormBase tdaf) {
182            // For now, until a more HtmlUnit based click method can be found
183            // workable, we're building a url-encoded string to directly
184            // post to the servlet.
185    
186            String url = baseUrl + buildPostFromFormParams(tdaf);
187            HtmlPage page = null;
188    
189            try {
190                page = HtmlUnitUtil.gotoPageAndLogin(webClient, url);
191            } catch (Exception e) {
192                LOG.error("Error while submitting form", e);
193            }
194    
195            return page;
196        }
197    
198        /**
199         * A method to wrap the submission of the time details.
200         * @param baseUrl
201         * @param tdaf
202         * @return
203         */
204        public static HtmlPage submitTimeDetails(WebClient webClient, String principalId, String baseUrl, TimeDetailActionFormBase tdaf) {
205            // For now, until a more HtmlUnit based click method can be found
206            // workable, we're building a url-encoded string to directly
207            // post to the servlet.
208    
209            String url = baseUrl + buildPostFromFormParams(tdaf);
210            HtmlPage page = null;
211    
212            try {
213                TestAutoLoginFilter.OVERRIDE_ID = principalId;
214                page = HtmlUnitUtil.gotoPageAndLogin(webClient, url);
215                TestAutoLoginFilter.OVERRIDE_ID = "";
216            } catch (Exception e) {
217                LOG.error("Error while submitting form", e);
218            }
219    
220            return page;
221        }
222    
223        private static String buildPostFromFormParams(TimeDetailActionFormBase tdaf) {
224            StringBuilder builder = new StringBuilder();
225    
226            try {
227                builder.append("&methodToCall=").append(URLEncoder.encode(tdaf.getMethodToCall(), "UTF-8"));
228                builder.append("&acrossDays=").append(URLEncoder.encode(tdaf.getAcrossDays(), "UTF-8"));
229                if (tdaf.getAmount() != null) {
230                    builder.append("&amount=").append(URLEncoder.encode(tdaf.getAmount().toString(), "UTF-8"));
231                } else {
232                    builder.append("&hours=").append(URLEncoder.encode(tdaf.getHours().toString(), "UTF-8"));
233                    builder.append("&startTime=").append(URLEncoder.encode(tdaf.getStartTime(), "UTF-8"));
234                    builder.append("&endTime=").append(URLEncoder.encode(tdaf.getEndTime(), "UTF-8"));
235                }
236                builder.append("&startDate=").append(URLEncoder.encode(tdaf.getStartDate(), "UTF-8"));
237                builder.append("&endDate=").append(URLEncoder.encode(tdaf.getEndDate(), "UTF-8"));
238                builder.append("&selectedAssignment=").append(URLEncoder.encode(tdaf.getSelectedAssignment(), "UTF-8"));
239                builder.append("&selectedEarnCode=").append(URLEncoder.encode(tdaf.getSelectedEarnCode(), "UTF-8"));
240                if (tdaf.getTkTimeBlockId() != null) {
241                    builder.append("&tkTimeBlockId=").append(URLEncoder.encode(tdaf.getTkTimeBlockId().toString(), "UTF-8"));
242                }
243            } catch (Exception e) {
244                LOG.error("Exception building Post String", e);
245            }
246    
247            return builder.toString();
248        }
249    }