Skip to content

Instantly share code, notes, and snippets.

@chriskearney
Created October 21, 2016 22:41
Show Gist options
  • Save chriskearney/190a6904eaa1e63620cad9d36f8cfd30 to your computer and use it in GitHub Desktop.
Save chriskearney/190a6904eaa1e63620cad9d36f8cfd30 to your computer and use it in GitHub Desktop.
package controllers;
import com.google.common.base.Optional;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import models.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.exceptions.COSVisitorException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDCheckbox;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.imgscalr.Scalr;
import play.Logger;
import play.mvc.Result;
import securesocial.core.java.SecureSocial;
import securesocial.core.java.SecuredAction;
import service.PDFUtil;
import service.SiteLogItemManager;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import static play.mvc.Controller.ctx;
import static play.mvc.Controller.response;
import static play.mvc.Results.ok;
public class PdfController {
public static Logger.ALogger logger = Logger.of("PdfController");
@SecuredAction
public static Result buildPdf(Long serviceCallId, boolean isFlatten) throws IOException, COSVisitorException, ParseException, InterruptedException {
Employee employee = (Employee) ctx().args.get(SecureSocial.USER_KEY);
ServiceCall serviceCall = ServiceCall.find.byId(serviceCallId);
SiteLogItemManager.createSiteLogItem(SiteLogItem.SiteLogItemType.GENERATE_PDF, employee.name, "Generated PDF for Service Call Id: " + serviceCallId, Optional.of(serviceCall.serviceCallNumber));
InputStream origPdfInputStream = PdfController.class.getResourceAsStream("/orig_pdf.pdf");
PDDocument load = PDDocument.load(origPdfInputStream);
response().setContentType("application/pdf");
return ok(buildReport(serviceCall, load, isFlatten));
}
private static byte[] buildReport(ServiceCall serviceCall, PDDocument pdDocument, boolean isFlatten) throws IOException, COSVisitorException, ParseException, InterruptedException {
if (serviceCall.serviceCallLink != null) {
ServiceCall serviceCallLink = ServiceCall.find.where().eq("service_call_number", serviceCall.serviceCallLink).findUnique();
setFieldValue(pdDocument, "S", String.valueOf(serviceCallLink.serviceCallNumber));
}
setFieldValue(pdDocument, "S", String.valueOf(serviceCall.serviceCallNumber));
Date dateOfCall = getDateFromString(serviceCall.dateOfCall);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM/dd/yyyy");
String dayOfCall = simpleDateFormat.format(dateOfCall);
simpleDateFormat = new SimpleDateFormat("hh:mm a");
String timeOfCall = simpleDateFormat.format(dateOfCall);
setFieldValue(pdDocument, "Date of Call", dayOfCall);
setFieldValue(pdDocument, "Time of Call", timeOfCall);
setFieldValue(pdDocument, "PO", serviceCall.purchaseOrderNumber);
setFieldValue(pdDocument, "Call Taken By", getShortName(serviceCall.callTakenBy));
setFieldValue(pdDocument, "Account Rep", getShortName(serviceCall.accountRep));
setFieldValue(pdDocument, "Customer Name", serviceCall.customer.name);
setFieldValue(pdDocument, "Job Location", serviceCall.jobSite.name);
setFieldValue(pdDocument, "Job Address", buildJobSiteAddress(serviceCall));
setFieldValue(pdDocument, "Office", serviceCall.customer.phoneNumber);
setFieldValue(pdDocument, "Jobsite", serviceCall.jobSite.phoneNumber);
setFieldValue(pdDocument, "Office Contact", serviceCall.customer.primaryContact);
setFieldValue(pdDocument, "Jobsite Contact", serviceCall.jobSite.primaryContact);
checkRoofTypeBox(pdDocument, serviceCall.roofType);
checkJobTypeBox(pdDocument, serviceCall.jobType);
fillOutServiceRequestDetailLines(pdDocument, serviceCall);
fillOutCauseWorkPerformed(pdDocument, serviceCall);
populateHours(pdDocument, serviceCall);
setFieldValue(pdDocument, "Date of Service", getTimeOfService(serviceCall));
populateSignature(pdDocument, serviceCall);
fillOutMaterialsUsed(pdDocument, serviceCall);
fillOurHoursForBilling(pdDocument, serviceCall);
fillOutTotalAmountToBill(pdDocument, serviceCall);
addAerialPhoto(pdDocument, serviceCall);
setFieldValue(pdDocument, "Jobsite Notes", serviceCall.jobSite.notes);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
if (isFlatten) {
PDFUtil.makeAllWidgetsReadOnly(pdDocument);
PDFUtil.flattenPDF(pdDocument);
}
pdDocument.save(byteArrayOutputStream);
pdDocument.close();
return byteArrayOutputStream.toByteArray();
}
static class BasicTextSorter implements Comparator<FieldTechWorkPerformed> {
public int compare(FieldTechWorkPerformed p1, FieldTechWorkPerformed p2) {
Date p1Date = null;
Date p2Date = null;
p1Date = getDateFromString(p1.timeOut);
p2Date = getDateFromString(p2.timeOut);
assert p1Date != null;
assert p2Date != null;
return p2Date.compareTo(p1Date);
}
}
private static String getTimeOfService(ServiceCall serviceCall) throws ParseException {
List<FieldTechWorkPerformed> fieldTechWorkPerformedItems = serviceCall.fieldTechWorkPerformedItems;
Collections.sort(fieldTechWorkPerformedItems, new BasicTextSorter());
if (fieldTechWorkPerformedItems.size() > 0) {
Date dateFromString = getDateFromString(fieldTechWorkPerformedItems.get(0).timeOut);
SimpleDateFormat formatter
= new SimpleDateFormat("MM/dd/yyyy");
return formatter.format(dateFromString);
} else {
return "";
}
}
private static void fillOutServiceRequestDetailLines(PDDocument pdDocument, ServiceCall serviceCall) throws IOException {
String details = "(Requested: " + serviceCall.dateOfService + ") " + serviceCall.serviceRequestDetails;
List<String> strings = splitString(details, 78);
String join = StringUtils.join(strings, "\r\n");
setFieldValue(pdDocument, "Service Request Details", join);
}
private static List<String> splitString(String input, int maxLineLength) {
StringTokenizer tok = new StringTokenizer(input, " ");
StringBuilder output = new StringBuilder(input.length());
int lineLen = 0;
while (tok.hasMoreTokens()) {
String word = tok.nextToken();
if (lineLen + word.length() > maxLineLength) {
output.append("\n");
lineLen = 0;
}
output.append(word).append(" ");
lineLen += word.length();
}
String[] split = output.toString().split("\\r?\\n");
return new ArrayList<>(Arrays.asList(split));
}
private static void addAerialPhoto(PDDocument pdDocument, ServiceCall serviceCall) throws IOException, InterruptedException {
if (serviceCall.serviceCallPhotos == null) {
return;
}
ServiceCallPhoto serviceCallP = null;
for (ServiceCallPhoto serviceCallPhoto : serviceCall.serviceCallPhotos) {
if (serviceCallPhoto.photoType.equals(ServiceCallPhotoType.AERIAL.getType())) {
serviceCallP = serviceCallPhoto;
}
}
if (serviceCallP == null) {
return;
}
PDPage pdPage = (PDPage) pdDocument.getDocumentCatalog().getAllPages().get(1);
PDPageContentStream stream = new PDPageContentStream(pdDocument, pdPage, true, true);
byte[] large = serviceCallP.getLarge();
final byte[] bytes = ServiceCallPhotosController.convertToJpg(large, 463, 210, Scalr.Mode.FIT_EXACT);
InputStream in = new ByteArrayInputStream(bytes);
BufferedImage bImageFromConvert = ImageIO.read(in);
PDJpeg img = new PDJpeg(pdDocument, bImageFromConvert);
stream.drawImage(img, 72, 538);
stream.close();
}
private static void fillOutMaterialsUsed(PDDocument pdDocument, ServiceCall serviceCall) throws IOException {
DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(2);
df.setMinimumFractionDigits(2);
int i = 1;
float totalCostToBeBilled = 0;
for (MaterialUsed materialUsed : ServiceCallController.getMaterialUsed(serviceCall)) {
String materialUsedField = "Material UsedRow" + i;
String amountUsedField = "Amount UsedRow" + i;
String itemCostField = "Item CostRow" + i;
String totalCostField = "Total CostRow" + i;
String materialUsedName = materialUsed.materialName;
if (isLinked(serviceCall)) {
materialUsedName = materialUsedName + " (SC" + serviceCall.serviceCallNumber + ")";
}
setFieldValue(pdDocument, materialUsedField, materialUsedName);
setFieldValue(pdDocument, amountUsedField, String.valueOf(materialUsed.materialAmount));
setFieldValue(pdDocument, itemCostField, "$" + df.format(materialUsed.itemCost));
float totalCost = materialUsed.itemCost * materialUsed.materialAmount;
totalCostToBeBilled += totalCost;
setFieldValue(pdDocument, totalCostField, "$" + df.format(totalCost));
i++;
}
if (serviceCall.serviceCallLink != null) {
ServiceCall serviceCallLinked = ServiceCall.find.byId(serviceCall.serviceCallLink);
if (serviceCallLinked != null) {
for (MaterialUsed materialUsed : ServiceCallController.getMaterialUsed(serviceCallLinked)) {
String materialUsedField = "Material UsedRow" + i;
String amountUsedField = "Amount UsedRow" + i;
String itemCostField = "Item CostRow" + i;
String totalCostField = "Total CostRow" + i;
setFieldValue(pdDocument, materialUsedField, materialUsed.materialName + " (SC" + serviceCallLinked.serviceCallNumber + ")");
setFieldValue(pdDocument, amountUsedField, String.valueOf(materialUsed.materialAmount));
setFieldValue(pdDocument, itemCostField, "$" + df.format(materialUsed.itemCost));
float totalCost = materialUsed.itemCost * materialUsed.materialAmount;
totalCostToBeBilled += totalCost;
setFieldValue(pdDocument, totalCostField, "$" + df.format(totalCost));
i++;
}
}
}
setFieldValue(pdDocument, "Total CostAmt", "$" + df.format(totalCostToBeBilled));
}
private static HoursAndMins getHoursAndMins(FieldTechWorkPerformed fieldTechWorkPerformed) throws ParseException {
Date timeIN = getDateFromString(fieldTechWorkPerformed.timeIn);
Date timeOUT = getDateFromString(fieldTechWorkPerformed.timeOut);
int secsForRate = (int) (timeOUT.getTime() - timeIN.getTime()) / 1000;
int minutesForRate = secsForRate / 60;
float minuteRate = fieldTechWorkPerformed.hourlyWage / 60;
float totalCost = minutesForRate * minuteRate;
int secs = (int) (timeOUT.getTime() - timeIN.getTime()) / 1000;
int hours = (int) (secs / 3600);
secs = secs % 3600;
int mins = (int) (secs / 60);
return new HoursAndMins(hours, mins, totalCost);
}
private static void fillOurHoursForBilling(PDDocument pdDocument, ServiceCall serviceCall) throws IOException, ParseException {
DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(2);
df.setMinimumFractionDigits(2);
float totalCostToBeBilled = 0;
totalCostToBeBilled += populateLaborRows(serviceCall, pdDocument, false);
if (serviceCall.serviceCallLink != null) {
ServiceCall serviceCallLinked = ServiceCall.find.where().eq("service_call_number", serviceCall.serviceCallLink).findUnique();
totalCostToBeBilled += populateLaborRows(serviceCallLinked, pdDocument, true);
}
setFieldValue(pdDocument, "Total CostAmt Labor", "$" + df.format(totalCostToBeBilled));
}
private static Map<String, List<FieldTechWorkPerformed>> getEmployeeWorkMap(List<FieldTechWorkPerformed> fieldTechWorkPerformedItems) {
Map<String, List<FieldTechWorkPerformed>> employeeWorkItemsMap = Maps.newLinkedHashMap();
for (FieldTechWorkPerformed fieldTechWorkPerformed : fieldTechWorkPerformedItems) {
if (!employeeWorkItemsMap.containsKey(fieldTechWorkPerformed.employeeName)) {
employeeWorkItemsMap.put(fieldTechWorkPerformed.employeeName, Lists.newArrayList());
}
employeeWorkItemsMap.get(fieldTechWorkPerformed.employeeName).add(fieldTechWorkPerformed);
}
return employeeWorkItemsMap;
}
private static float populateLaborRows(ServiceCall serviceCall, PDDocument pdDocument, boolean isLinked) throws IOException, ParseException {
DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(2);
df.setMinimumFractionDigits(2);
Map<String, List<FieldTechWorkPerformed>> employeeWorkItemsMap = getEmployeeWorkMap(ServiceCallController.getFieldTechWorkPerformedItems(serviceCall));
int i = 1;
float totalCostToBeBilled = 0;
for (Map.Entry<String, List<FieldTechWorkPerformed>> entry : employeeWorkItemsMap.entrySet()) {
List<FieldTechWorkPerformed> workPerformeds = entry.getValue();
String employeeName = entry.getKey();
String technicianNameField = "Technicians " + i;
String technicianHoursField = "HoursRow" + i;
String technicianRatePerHour = "Rate per HourRow" + i;
String techniciantotalCostRow = "Total CostRow" + i + "_2";
float rowCost = 0;
int hours = 0;
int mins = 0;
float hourlyWage = 0;
for (FieldTechWorkPerformed workPerformed : workPerformeds) {
hourlyWage = workPerformed.hourlyWage;
HoursAndMins hoursAndMins = getHoursAndMins(workPerformed);
rowCost += hoursAndMins.getTotalCost();
hours += hoursAndMins.getHours();
mins += hoursAndMins.getMinutes();
}
if (isLinked(serviceCall)) {
employeeName = employeeName + " (SC" + serviceCall.serviceCallNumber + ")";
}
if (isLinked) {
setFieldValue(pdDocument, technicianNameField, employeeName + " (SC" + serviceCall.serviceCallNumber + ")");
} else {
setFieldValue(pdDocument, technicianNameField, employeeName);
}
setFieldValue(pdDocument, technicianHoursField, hours + "h " + mins + "m");
setFieldValue(pdDocument, technicianRatePerHour, "$" + df.format(hourlyWage));
totalCostToBeBilled += rowCost;
setFieldValue(pdDocument, techniciantotalCostRow, "$" + df.format(rowCost));
i++;
}
return totalCostToBeBilled;
}
private static void setFieldValue(PDDocument pdDocument, String fieldName, String value) throws IOException {
if (value == null) {
return;
}
PDDocumentCatalog docCatalog = pdDocument.getDocumentCatalog();
PDAcroForm acroForm = docCatalog.getAcroForm();
acroForm.getField(fieldName).setValue(value);
}
private static void checkRoofTypeBox(PDDocument pdDocument, String type) throws IOException {
PDAcroForm form = pdDocument.getDocumentCatalog().getAcroForm();
RoofType roofType = RoofType.getFromString(type);
PDField field = form.getField(roofType.getPdfFieldName());
((PDCheckbox) field).check();
}
private static void checkJobTypeBox(PDDocument pdDocument, String type) throws IOException {
PDAcroForm form = pdDocument.getDocumentCatalog().getAcroForm();
JobType jobType = JobType.getFromString(type);
PDField field = form.getField(jobType.getPdfFieldName());
((PDCheckbox) field).check();
}
private static void fillOutCauseWorkPerformed(PDDocument pdDocument, ServiceCall serviceCall) throws IOException {
List<FieldTechWorkPerformed> fieldTechWorkPerformedItems = ServiceCallController.getFieldTechWorkPerformedItems(serviceCall);
Set<String> workCauseDescriptions = fieldTechWorkPerformedItems.stream().map(sc -> sc.fieldTechWorkPerformedDescription).collect(Collectors.toSet());
fieldTechWorkPerformedItems.stream().map(sc -> sc.fieldTechWorkPerformedDescription).collect(Collectors.toSet());
int i = 1;
for (String description : workCauseDescriptions) {
String currentField = "Work Performed " + i;
i++;
if (isLinked(serviceCall)) {
description = description + " (SC" + serviceCall.serviceCallNumber + ")";
}
setFieldValue(pdDocument, currentField, description);
}
if (serviceCall.serviceCallLink != null) {
ServiceCall serviceCallLinked = ServiceCall.find.byId(serviceCall.serviceCallLink);
if (serviceCallLinked != null) {
for (String description : ServiceCallController.getFieldTechWorkPerformedItems(serviceCallLinked).stream().map(sc -> sc.fieldTechWorkPerformedDescription).collect(Collectors.toSet())) {
String currentField = "Work Performed " + i;
i++;
setFieldValue(pdDocument, currentField, description + " (SC" + serviceCallLinked.serviceCallNumber + ")");
}
}
}
}
private static boolean isLinked(ServiceCall serviceCall) {
if (serviceCall.serviceCallLink != null) {
return true;
}
return false;
}
private static String getShortName(String fullName) {
List<String> split = Arrays.asList(fullName.split("\\s+"));
if (split.size() > 1) {
String lastName = split.get(split.size() - 1);
String firstInitial = String.valueOf(split.get(0).toCharArray()[0]);
return firstInitial + " " + lastName;
} else {
return fullName;
}
}
public static Date getDateFromString(String stringDate) {
Date returnDate = new Date(0);
try {
DateFormat format = new SimpleDateFormat("MM/dd/yyyy hh:mm a");
returnDate = format.parse(stringDate);
} catch (Exception e) {
logger.error("Unable to parse date, or empty.");
}
return returnDate;
}
private static HoursAndMins getHoursAndMinsForType(List<FieldTechWorkPerformed> fieldTechWorkPerformeds, String type) throws ParseException {
int totalHours = 0;
int totalMins = 0;
for (FieldTechWorkPerformed fieldTechWorkPerformed : fieldTechWorkPerformeds) {
if (fieldTechWorkPerformed.workType.equalsIgnoreCase(type)) {
HoursAndMins hoursAndMins = getHoursAndMins(fieldTechWorkPerformed);
totalHours += hoursAndMins.getHours();
totalMins += hoursAndMins.getMinutes();
}
}
return new HoursAndMins(totalHours, totalMins, 0);
}
private static void filloutHours(PDDocument pdDocument, ServiceCall serviceCall, boolean isLinked) throws ParseException, IOException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("hh:mm a");
int i = 1;
Map<String, List<FieldTechWorkPerformed>> employeeWorkMap = getEmployeeWorkMap(ServiceCallController.getFieldTechWorkPerformedItems(serviceCall));
for (Map.Entry<String, List<FieldTechWorkPerformed>> entry : employeeWorkMap.entrySet()) {
int totalHours = 0;
int totalMins = 0;
Date oldest = getOldestdate(entry.getValue());
Date newest = getNewestdate(entry.getValue());
Set<String> workTypes = entry.getValue().stream().map(f -> f.workType).collect(Collectors.toSet());
Map<String, HoursAndMins> hoursAndMinsByType = Maps.newLinkedHashMap();
for (String type : workTypes) {
HoursAndMins hoursAndMinsForType = getHoursAndMinsForType(entry.getValue(), type);
hoursAndMinsByType.put(type, hoursAndMinsForType);
}
if (isLinked(serviceCall) || isLinked) {
setFieldValue(pdDocument, "Page 1 Technicians " + i, entry.getKey() + " (SC" + serviceCall.serviceCallNumber + ")");
} else {
setFieldValue(pdDocument, "Page 1 Technicians " + i, entry.getKey());
}
String timeIn = simpleDateFormat.format(oldest);
setFieldValue(pdDocument, "Time In " + i, timeIn);
String timeOut = simpleDateFormat.format(newest);
setFieldValue(pdDocument, "Time Out " + i, timeOut);
for (Map.Entry<String, HoursAndMins> e : hoursAndMinsByType.entrySet()) {
HoursAndMins hoursAndMins = e.getValue();
totalHours += hoursAndMins.getHours();
totalMins += hoursAndMins.getMinutes();
FieldTechWorkPerformedTimeType byType = FieldTechWorkPerformedTimeType.getByType(e.getKey());
setFieldValue(pdDocument, byType.getPdfFieldName() + " " + i, hoursAndMins.getHours() + "h " + hoursAndMins.getMinutes() + "m");
}
totalMins += (totalHours * 60);
int hours = totalMins / 60; //since both are ints, you get an int
int minutes = totalMins % 60;
setFieldValue(pdDocument, "Total time row" + " " + i, hours + "h " + minutes + "m");
i++;
}
}
private static void populateHours(PDDocument pdDocument, ServiceCall serviceCall) throws IOException, ParseException {
filloutHours(pdDocument, serviceCall, false);
if (serviceCall.serviceCallLink != null) {
ServiceCall serviceCallLinked = ServiceCall.find.where().eq("service_call_number", serviceCall.serviceCallLink).findUnique();
filloutHours(pdDocument, serviceCallLinked, true);
}
}
private static void populateSignature(PDDocument pdDocument, ServiceCall serviceCall) throws IOException {
if (serviceCall.signature == null) {
return;
}
PDPage pdPage = (PDPage) pdDocument.getDocumentCatalog().getAllPages().get(0);
PDPageContentStream stream = new PDPageContentStream(pdDocument, pdPage, true, true);
byte[] signatureImageThumbJpeg = serviceCall.signature.getSignatureImageThumbJpeg();
InputStream in = new ByteArrayInputStream(signatureImageThumbJpeg);
BufferedImage bImageFromConvert = ImageIO.read(in);
PDJpeg img = new PDJpeg(pdDocument, bImageFromConvert);
stream.drawImage(img, 310, 30);
stream.close();
}
private static void fillOutTotalAmountToBill(PDDocument pdDocument, ServiceCall serviceCall) throws ParseException, IOException {
DecimalFormat df = new DecimalFormat();
df.setMaximumFractionDigits(2);
df.setMinimumFractionDigits(2);
float totalToBill = 0;
for (MaterialUsed materialUsed : ServiceCallController.getMaterialUsed(serviceCall)) {
totalToBill += materialUsed.itemCost * materialUsed.materialAmount;
}
for (FieldTechWorkPerformed fieldTechWorkPerformed : ServiceCallController.getFieldTechWorkPerformedItems(serviceCall)) {
Date timeIN = getDateFromString(fieldTechWorkPerformed.timeIn);
Date timeOUT = getDateFromString(fieldTechWorkPerformed.timeOut);
int secsForRate = (int) (timeOUT.getTime() - timeIN.getTime()) / 1000;
int minutesForRate = secsForRate / 60;
float minuteRate = fieldTechWorkPerformed.hourlyWage / 60;
totalToBill += minutesForRate * minuteRate;
}
setFieldValue(pdDocument, "Amount to Bill", "$" + df.format(totalToBill));
}
private static Date getOldestdate(List<FieldTechWorkPerformed> workPerformeds) throws ParseException {
Date oldest = null;
List<String> timeInDateStrings = workPerformeds.stream().map(w -> w.timeIn).collect(Collectors.toList());
for (String dateString : timeInDateStrings) {
Date dateFromString = getDateFromString(dateString);
if (oldest == null) {
oldest = dateFromString;
} else {
Date least = least(dateFromString, oldest);
oldest = least;
}
}
return oldest;
}
public static Date least(Date a, Date b) {
return a == null ? b : (b == null ? a : (a.before(b) ? a : b));
}
private static Date getNewestdate(List<FieldTechWorkPerformed> workPerformeds) throws ParseException {
List<String> timeOutStrings = workPerformeds.stream().map(d -> d.timeOut).collect(Collectors.toList());
List<Date> dates = Lists.newArrayList();
for (String d: timeOutStrings) {
Date dateFromString = getDateFromString(d);
dates.add(dateFromString);
}
Collections.sort(dates);
return dates.get(dates.size() - 1);
}
private static String buildJobSiteAddress(ServiceCall serviceCall) {
String streetAddress = serviceCall.jobSite.streetAddress;
String city = serviceCall.jobSite.city;
String zipCode = serviceCall.jobSite.zipCode;
String state = serviceCall.jobSite.state;
return streetAddress + " " + city + ", " + state + " " + zipCode;
}
public static class HoursAndMins {
private final int hours;
private final int minutes;
private final float totalCost;
public HoursAndMins(int hours, int minutes, float totalCost) {
this.hours = hours;
this.minutes = minutes;
this.totalCost = totalCost;
}
public int getHours() {
return hours;
}
public int getMinutes() {
return minutes;
}
public float getTotalCost() {
return totalCost;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment