Skip to content

Instantly share code, notes, and snippets.

@aishfenton
Created September 5, 2011 04:32
Show Gist options
  • Select an option

  • Save aishfenton/1194096 to your computer and use it in GitHub Desktop.

Select an option

Save aishfenton/1194096 to your computer and use it in GitHub Desktop.

Revisions

  1. Aish revised this gist Oct 18, 2011. 1 changed file with 2 additions and 4 deletions.
    6 changes: 2 additions & 4 deletions vworkapp.js
    Original file line number Diff line number Diff line change
    @@ -1,12 +1,10 @@
    // vWorkAppScript - vWorkApp core library
    // ------------------------------------------------------------------------------------------------------------------//
    // vWorkApp Core Library
    // ------------------------------------------------------------------------------------------------------------------//

    var vWorkAppScript = vWorkAppScript || {};

    vWorkAppScript.host = "api.vworkapp.com";
    vWorkAppScript.apiToken = configSheet.getRange(2,2).getValue().trim();
    vWorkAppScript._spreadsheet = spreadsheet;
    vWorkAppScript.apiToken = "PUT YOUR API KEY HERE"

    (function() {

  2. Aish revised this gist Oct 12, 2011. 1 changed file with 1 addition and 71 deletions.
    72 changes: 1 addition & 71 deletions vworkapp.js
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,3 @@

    // vWorkAppScript - vWorkApp core library
    // ------------------------------------------------------------------------------------------------------------------//
    // ------------------------------------------------------------------------------------------------------------------//
    @@ -294,81 +293,12 @@ vWorkAppScript._spreadsheet = spreadsheet;
    Logger.log("Geocoding Failed: Address is " + address);
    return { lat: '', lng: '' };
    }
    }

    // SHEET DATA HANDLING
    // ------------------------------------------------------------------------------------------------------------------//

    this.formatJSONtoSheet = function(sheetName, objects, headersRange, rowOffset){

    var sheet = this._spreadsheet.getSheetByName(sheetName);
    var headers = this.normalizeHeaders(headersRange.getValues()[0]);
    var data = [];
    for (var i = 0; i < objects.length; ++i) {
    var values = [];
    for (j = 0; j < headers.length; ++j) {
    var header = headers[j];
    values.push( ((header.length > 0) && (objects[i][header])) ? objects[i][header] : "");
    }
    data.push(values);
    }
    var destinationRange = sheet.getRange(rowOffset, headersRange.getColumnIndex(), objects.length, headers.length);
    destinationRange.setValues(data);
    }

    this.normalizeHeaders = function(headers){
    var keys = [];
    for (var i = 0; i < headers.length; ++i) {
    keys.push(this.normalizeHeader(headers[i]));
    }
    return keys;
    }

    this.normalizeHeader = function(header) {
    var key = "";
    var upperCase = false;
    for (var i = 0; i < header.length; ++i) {
    var letter = header[i];
    if (letter == " " && key.length > 0) {
    upperCase = true;
    continue;
    }

    if (upperCase) {
    upperCase = false;
    key += letter.toUpperCase();
    } else {
    key += letter.toLowerCase();
    }
    }
    return key;
    }


    // SHEET XTRL
    // ------------------------------------------------------------------------------------------------------------------//

    this.emptySheet = function(sheetName){
    this._spreadsheet.getSheetByName(sheetName).clear();
    }

    this.clearRange = function(sheetName, startRow,startCol,endRow,endCol){
    this._spreadsheet.getSheetByName(sheetName).getRange(startRow,startCol,endRow,endCol).clear();
    }

    this.showSheetMessage = function(sheetName, message, displayRow, displayCol){
    this._spreadsheet.getSheetByName(sheetName).getRange(displayRow, displayCol, 1, 1).setValue(message);
    }

    }

    }).apply(vWorkAppScript);







    // vWorkAppUitls - vWorkApp utility library
    // ------------------------------------------------------------------------------------------------------------------//
    // ------------------------------------------------------------------------------------------------------------------//
  3. Aish revised this gist Oct 12, 2011. 1 changed file with 434 additions and 132 deletions.
    566 changes: 434 additions & 132 deletions vworkapp.js
    Original file line number Diff line number Diff line change
    @@ -1,133 +1,435 @@
    var spreadSheetID = "0Aq3G_rdwnXT1dFdBZUo5V3BWTGJOdVJySFQxOE1KRHc";
    var ss = SpreadsheetApp.getActiveSpreadsheet()
    var configSheet = ss.getSheetByName("Settings");

    //var customFieldLimit = 20;
    var host = "api.vworkapp.com"

    // These must be defined in the Tools sheet
    var apiToken = configSheet.getRange(2,2).getValue().trim();

    function createJobs() {
    var jobsSheet = ss.getActiveSheet();

    var templateName = jobsSheet.getRange(1, 2).getValue() + '';
    var stepCount = jobsSheet.getRange(2, 2).getValue();
    var cfCount = jobsSheet.getRange(3, 2).getValue();

    // Each Job
    var count = 0;
    var lastRow = jobsSheet.getLastRow();
    for (row = 6; row <= lastRow; row++) {

    var customerName = jobsSheet.getRange(row, 1).getValue() + '';
    var duration = (jobsSheet.getRange(row, 2).getValue() * 60) + '';

    if (customerName == "" || duration == "") {
    break;
    }

    var when = new Date(jobsSheet.getRange(row, 8).getValue()).toISOString();
    var who = jobsSheet.getRange(row, 8).getValue();

    // Steps
    var steps = [];
    for (i=0; i < stepCount; i++) {
    var startCol = 3;
    var stepName = jobsSheet.getRange(5, startCol + i).getValue() + '';
    var stepAddress = jobsSheet.getRange(row, startCol + i).getValue() + '';
    var stepLocation = geocodeAddress(stepAddress);
    var stepData = {
    name: stepName,
    location: {formatted_address: stepAddress, lat: stepLocation.lat, lng: stepLocation.lng}
    };

    steps.push(stepData);
    }

    // Custom Fields
    var fields = [];
    for (i=0; i < cfCount; i++) {
    var startCol = 3 + stepCount;
    var cfName = jobsSheet.getRange(5, startCol + i).getValue() + '';
    var cfValue = jobsSheet.getRange(row, startCol + i).getValue() + '';
    var cfData = {
    name: cfName,
    value: cfValue
    };

    fields.push(cfData);
    }

    var vWorkApp = new vWorkAppAPI();
    //vWorkApp.createJob(customerName, templateName, duration, steps, fields);
    count++;
    }

    Browser.msgBox("vWorkApp", count + " jobs imported!", Browser.Buttons.OK);

    function geocodeAddress(address) {
    var geocoder = Maps.newGeocoder();
    try {
    var geoJSON = geocoder.geocode(address);
    return geoJSON.results[0].geometry.location;
    } catch(e) {
    Logger.log("Geocoding Failed: Address is " + address);
    return { lat: '', lng: '' };
    }
    }
    };


    // ------
    // General util
    // ------
    String.prototype.trim = function() {
    return this.replace(/^\s+|\s+$/g,"");
    }


    // ------
    // vWorkApp API Class
    // ------

    vWorkAppAPI = function() {

    this.posthttp = function(url, payload) {
    Logger.log(JSON.stringify(payload));

    var advancedArgs = {
    method: "post",
    payload: JSON.stringify(payload),
    contentType: "application/json; charset=UTF-8"
    };

    Logger.log("Creating Job. Response was:" + UrlFetchApp.fetch(url, advancedArgs));
    };

    };

    vWorkAppAPI.prototype = {

    // --
    // Creates a job in vWorkApp.
    //
    //
    createJob: function(customerName, templateName, duration, steps, custom_fields) {
    var payload = {
    job: {
    customer_name: customerName,
    template_name: templateName,
    planned_duration: duration,
    steps: steps,
    custom_fields: custom_fields
    }
    };

    var url = "https://" + host + "/2.0/jobs?api_key=" + apiToken;
    this.posthttp(url, payload);

    }

    }

    // vWorkAppScript - vWorkApp core library
    // ------------------------------------------------------------------------------------------------------------------//
    // ------------------------------------------------------------------------------------------------------------------//

    var vWorkAppScript = vWorkAppScript || {};

    vWorkAppScript.host = "api.vworkapp.com";
    vWorkAppScript.apiToken = configSheet.getRange(2,2).getValue().trim();
    vWorkAppScript._spreadsheet = spreadsheet;

    (function() {

    // CONFIGURATION
    // ------------------------------------------------------------------------------------------------------------------//

    //required fields
    var _spreadsheet;
    var apiToken;
    var host;

    //optional fields
    var recordsPerPage = 100;
    var dataDecorator = null;


    // API HELPER
    // ------------------------------------------------------------------------------------------------------------------//

    this.loadData = function(url){
    var result = this.loadDataPage(url,1);
    return [Xml.parse(result, true)];
    }

    this.loadPagedData = function(url){
    var page = 1;
    var results = [];
    var result = this.loadDataPage(url,1);
    var xmlDoc = Xml.parse(result, true);
    var pages = parseInt(xmlDoc.getElement().getAttribute("total_pages").getValue());

    results.push(xmlDoc);
    for(var i = 2; i <= pages; i++) {
    results.push(Xml.parse(this.loadDataPage(url,i), true));
    }
    return results;
    }

    this.loadDataPage = function(url, page) {
    var parameters = this.generateRequestHeader("get");
    var requestURL = url + "&per_page="+recordsPerPage+"&page=" + page;
    var result;
    try {
    result = UrlFetchApp.fetch(requestURL, parameters).getContentText();
    } catch(e){
    Logger.log("I/O Failure: "+e);
    Browser.msgBox("We are sorry but we are unable to process your request at this time. Please try again later.");
    }
    return result;
    }

    this.postAsJSON = function(url, payload, method) {
    if (method == null)
    method = 'post';
    var args = this.generateRequestHeader(
    method, {
    payload: JSON.stringify(payload),
    contentType: "application/json; charset=UTF-8"
    }
    );
    UrlFetchApp.fetch(url, args);
    };


    // URL HELPER
    // ------------------------------------------------------------------------------------------------------------------//

    this.buildURL = function(resource, ext, identifier, useThirdParty){
    var str = resource + ((identifier == null) ? "" : "/"+identifier) + ((ext == null) ? "" : ext);
    return "https://" + this.host + "/2.0/"+ str + "?api_key=" + this.apiToken + ((useThirdParty) ? "&use_third_party_id=true" : '');
    }

    this.explodeURLParameters = function(params){
    var s = '';
    var value;
    for(var key in params){
    value = params[key];
    key = escape(key); value = escape(value);
    var kvp = key+"="+value;
    var r = new RegExp("(&|\\?)"+key+"=[^\&]*");
    s = s.replace(r,"$1"+kvp);
    if(!RegExp.$1) {s += '&' + kvp;};
    }
    return s;
    }

    this.generateRequestHeader = function(method, arguments){
    if (arguments == null) arguments = {};
    arguments['method'] = method;
    arguments['headers'] = { "Accept-Encoding": "gzip,deflate" }
    return arguments;
    }

    // JOBS
    // ------------------------------------------------------------------------------------------------------------------//

    this.loadJobByIdentifier = function(jobId, isThirdParty){
    var url = this.buildURL("jobs",".xml",jobId,isThirdParty);
    return this.loadData(url);
    };

    this.loadJobsForParameters = function(params){
    var url = this.buildURL("jobs",".xml") + this.explodeURLParameters(params);
    return this.loadData(url);
    }

    this.loadJobsForList = function(list,useThirdParty){
    var jobsAsXML = [];
    for (var idIterator = 0; idIterator < list.length; idIterator++) {
    jobsAsXML.push(this.loadJobByIdentifier(list[idIterator].trim(),useThirdParty));
    }
    return jobsAsXML;
    }

    this.createJob = function(customerName, templateName, duration, steps, custom_fields) {
    var payload = {
    job: {
    customer_name: customerName,
    template_name: templateName,
    planned_duration: duration,
    steps: steps,
    custom_fields: custom_fields
    }
    };
    var url = this.buildURL('jobs');
    this.postAsJSON(url, payload);
    }

    this.updateJob = function(jobAsJSON){
    var job = {};
    for (var property in jobAsJSON){
    job[vWorkAppUtils.toUnderscore(property)] = jobAsJSON[property];
    }
    var payload = { job: job };
    var url = this.buildURL('jobs','.xml',job.id);
    this.postAsJSON(url, payload, 'put');
    }



    this.jobFlattenCustomFields = function(job){
    // WARNING - this method will clone job and return all custom fields as root elements keyed on name
    var jobClone = {}; var property;
    for(property in job){
    jobClone[property] = job[property];
    }
    for(property in job.customFields){
    jobClone[this.normalizeHeader(job.customFields[property].name)] = job.customFields[property].value;
    }
    return jobClone;
    }

    this.jobRebuildCustomFields = function(job,stdHeaders,cfHeaders){
    // WARNING - this method assumes that anything not in stdHeaders is a custom field keyed on name
    var normalizedStdHeaders = vWorkAppScript.normalizeHeaders(stdHeaders);
    var normalizedCfHeaders = vWorkAppScript.normalizeHeaders(cfHeaders);
    var jobClone = {}; var customFields = []; var property;
    for(property in job){
    if (normalizedStdHeaders.indexOf(property) == -1){
    if (normalizedCfHeaders.indexOf(property) == -1)
    continue;
    customFields.push({
    name:cfHeaders[normalizedCfHeaders.indexOf(property)],
    value:job[property]
    });
    continue;
    }
    jobClone[property] = job[property];
    }
    jobClone.customFields = customFields;
    return jobClone;
    }



    // PROOF OF DELIVERY
    // ------------------------------------------------------------------------------------------------------------------//

    this.getProofOfDeliveryURL = function(jobId){
    return "https://" + this.host + "/2.0/jobs/" + jobId + "/proof_of_delivery.png?api_key=" + this.apiToken;
    }


    // CUSTOM FIELDS
    // ------------------------------------------------------------------------------------------------------------------//




    // DATA PARSERS
    // ------------------------------------------------------------------------------------------------------------------//

    this.jobsXMLtoJSON = function(jobsXML){

    var jobXMLArray = jobsXML.jobs.getElements("job");
    if (jobXMLArray.length == 0) return {};

    var jobsData = []; var jobData;
    for(var i = 0; i < jobXMLArray.length; i++) {
    jobXML = jobXMLArray[i];
    jobsData.push(this.jobXMLtoJSON(jobXML));
    }
    return jobsData;
    }

    this.jobXMLtoJSON = function(jobXML){

    if(jobXML.getElement('id') == null)
    return {};

    var jobData = {
    id: jobXML.getElement('id').getText(),
    jobName: jobXML.getElement('template_name').getText(),
    customerName: jobXML.getElement('customer_name').getText(),
    workerName: jobXML.getElement('worker_name').getText(),
    proofOfDelivery: (jobXML.getElement('has_pod').getText() == "true") ? this.getProofOfDeliveryURL(jobXML.getElement('id').getText()) : "",
    steps: this.stepsXMLtoJSON(jobXML.getElement('steps')),
    customFields: this.customFieldXMLtoJSON(jobXML.getElement('custom_fields')),
    progressState: jobXML.getElement('progress_state').getText(),
    actualDuration: jobXML.getElement('actual_duration').getText(),
    plannedDuration: jobXML.getElement('planned_duration').getText(),
    plannedStartAt: jobXML.getElement('planned_start_at').getText(),
    plannedEndAt: jobXML.getElement('planned_end_at').getText(),
    actualStartAt: jobXML.getElement('actual_start_at').getText()
    }

    if (this.dataDecorator != null)
    this.dataDecorator.run("job", jobData);

    return jobData;
    }


    this.customFieldXMLtoJSON = function(customFieldNode){
    var cfXMLArray = customFieldNode.getElements("custom_field");
    var customFieldsData = []; var customFieldData;
    for(var c = 0; c < cfXMLArray.length; c++) {
    var cfXML = cfXMLArray[c];
    customFieldData = {
    name: cfXML.name.getText(),
    value: cfXML.value.getText(),
    type: cfXML.type.getText()
    }
    customFieldsData.push(customFieldData);
    }

    return customFieldsData;
    }

    this.stepsXMLtoJSON = function(stepNode){
    var stepsXMLArray = stepNode.getElements("step");
    var stepsData = []; var stepData;
    for(var s = 0; s < stepsXMLArray.length; s++) {
    var stepXML = stepsXMLArray[s];
    stepData = {
    id: stepXML.id.getText(),
    name: stepXML.name.getText(),
    completedAt: stepXML.completed_at.getText(),
    location: this.locationXMLtoJSON(stepXML.location)
    }
    stepsData.push(stepData);
    }
    return stepsData;
    }

    this.locationXMLtoJSON = function(locationNode){
    return {
    id: locationNode.id.getText(),
    formattedAddress: locationNode.formatted_address.getText(),
    lat: locationNode.lat.getText(),
    lng: locationNode.lng.getText()
    }
    }

    // GEOUTILS
    // ------------------------------------------------------------------------------------------------------------------//

    this.geocodeAddress = function(address) {
    var geocoder = Maps.newGeocoder();
    try {
    var geoJSON = geocoder.geocode(address);
    return geoJSON.results[0].geometry.location;
    } catch(e) {
    Logger.log("Geocoding Failed: Address is " + address);
    return { lat: '', lng: '' };
    }
    }

    // SHEET DATA HANDLING
    // ------------------------------------------------------------------------------------------------------------------//

    this.formatJSONtoSheet = function(sheetName, objects, headersRange, rowOffset){

    var sheet = this._spreadsheet.getSheetByName(sheetName);
    var headers = this.normalizeHeaders(headersRange.getValues()[0]);
    var data = [];
    for (var i = 0; i < objects.length; ++i) {
    var values = [];
    for (j = 0; j < headers.length; ++j) {
    var header = headers[j];
    values.push( ((header.length > 0) && (objects[i][header])) ? objects[i][header] : "");
    }
    data.push(values);
    }
    var destinationRange = sheet.getRange(rowOffset, headersRange.getColumnIndex(), objects.length, headers.length);
    destinationRange.setValues(data);
    }

    this.normalizeHeaders = function(headers){
    var keys = [];
    for (var i = 0; i < headers.length; ++i) {
    keys.push(this.normalizeHeader(headers[i]));
    }
    return keys;
    }

    this.normalizeHeader = function(header) {
    var key = "";
    var upperCase = false;
    for (var i = 0; i < header.length; ++i) {
    var letter = header[i];
    if (letter == " " && key.length > 0) {
    upperCase = true;
    continue;
    }

    if (upperCase) {
    upperCase = false;
    key += letter.toUpperCase();
    } else {
    key += letter.toLowerCase();
    }
    }
    return key;
    }


    // SHEET XTRL
    // ------------------------------------------------------------------------------------------------------------------//

    this.emptySheet = function(sheetName){
    this._spreadsheet.getSheetByName(sheetName).clear();
    }

    this.clearRange = function(sheetName, startRow,startCol,endRow,endCol){
    this._spreadsheet.getSheetByName(sheetName).getRange(startRow,startCol,endRow,endCol).clear();
    }

    this.showSheetMessage = function(sheetName, message, displayRow, displayCol){
    this._spreadsheet.getSheetByName(sheetName).getRange(displayRow, displayCol, 1, 1).setValue(message);
    }


    }).apply(vWorkAppScript);







    // vWorkAppUitls - vWorkApp utility library
    // ------------------------------------------------------------------------------------------------------------------//
    // ------------------------------------------------------------------------------------------------------------------//



    var vWorkAppUtils = vWorkAppUtils || {};

    (function() {

    this.ISODateString = function(d){
    function pad(n){ return n < 10 ? '0'+ n : n }
    return d.getUTCFullYear()+'-'
    + pad(d.getUTCMonth()+1)+'-'
    + pad(d.getUTCDate())+'T'
    + pad(d.getUTCHours())+':'
    + pad(d.getUTCMinutes())+':'
    + pad(d.getUTCSeconds())+'Z'
    }

    this.xmlDateToJavascriptDate = function(xmlDate) {
    var re = /^([0-9]{4,})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(\.[0-9]+)?(Z|([+-])([0-9]{2}):([0-9]{2}))?$/;
    var match = xmlDate.match(re);
    if (!match)
    return null;

    var all = match[0];
    var year = match[1]; var month = match[2] - 1; var day = match[3];
    var hour = match[4]; var minute = match[5]; var second = match[6];
    var milli = match[7];
    var z_or_offset = match[8]; var offset_sign = match[9];
    var offset_hour = match[10]; var offset_minute = match[11];

    if (offset_sign) {
    var direction = (offset_sign == "+" ? 1 : -1);
    hour = parseInt(hour) + parseInt(offset_hour) * direction;
    minute = parseInt(minute) + parseInt(offset_minute) * direction;
    }

    var utcDate = Date.UTC(year, month, day, hour, minute, second, (milli || 0));
    return new Date(utcDate);
    }

    this.toUnderscore = function(str){
    str = str.substr(0,1).toLowerCase() + str.substr(1,str.length);
    return str.replace(/([A-Z])/g, function($1){return "_"+$1.toLowerCase();});
    }

    this.secondsToTime = function(seconds){

    var h = Math.floor(seconds / (60 * 60));

    var divisor_for_minutes = seconds % (60 * 60);
    var m = Math.floor(divisor_for_minutes / 60);

    var divisor_for_seconds = divisor_for_minutes % 60;
    var s = Math.ceil(divisor_for_seconds);

    return h + "h "+m+"m "+s+"s";
    }


    }).apply(vWorkAppUtils);

  4. Aish created this gist Sep 5, 2011.
    133 changes: 133 additions & 0 deletions vworkapp.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,133 @@
    var spreadSheetID = "0Aq3G_rdwnXT1dFdBZUo5V3BWTGJOdVJySFQxOE1KRHc";
    var ss = SpreadsheetApp.getActiveSpreadsheet()
    var configSheet = ss.getSheetByName("Settings");

    //var customFieldLimit = 20;
    var host = "api.vworkapp.com"

    // These must be defined in the Tools sheet
    var apiToken = configSheet.getRange(2,2).getValue().trim();

    function createJobs() {
    var jobsSheet = ss.getActiveSheet();

    var templateName = jobsSheet.getRange(1, 2).getValue() + '';
    var stepCount = jobsSheet.getRange(2, 2).getValue();
    var cfCount = jobsSheet.getRange(3, 2).getValue();

    // Each Job
    var count = 0;
    var lastRow = jobsSheet.getLastRow();
    for (row = 6; row <= lastRow; row++) {

    var customerName = jobsSheet.getRange(row, 1).getValue() + '';
    var duration = (jobsSheet.getRange(row, 2).getValue() * 60) + '';

    if (customerName == "" || duration == "") {
    break;
    }

    var when = new Date(jobsSheet.getRange(row, 8).getValue()).toISOString();
    var who = jobsSheet.getRange(row, 8).getValue();

    // Steps
    var steps = [];
    for (i=0; i < stepCount; i++) {
    var startCol = 3;
    var stepName = jobsSheet.getRange(5, startCol + i).getValue() + '';
    var stepAddress = jobsSheet.getRange(row, startCol + i).getValue() + '';
    var stepLocation = geocodeAddress(stepAddress);
    var stepData = {
    name: stepName,
    location: {formatted_address: stepAddress, lat: stepLocation.lat, lng: stepLocation.lng}
    };

    steps.push(stepData);
    }

    // Custom Fields
    var fields = [];
    for (i=0; i < cfCount; i++) {
    var startCol = 3 + stepCount;
    var cfName = jobsSheet.getRange(5, startCol + i).getValue() + '';
    var cfValue = jobsSheet.getRange(row, startCol + i).getValue() + '';
    var cfData = {
    name: cfName,
    value: cfValue
    };

    fields.push(cfData);
    }

    var vWorkApp = new vWorkAppAPI();
    //vWorkApp.createJob(customerName, templateName, duration, steps, fields);
    count++;
    }

    Browser.msgBox("vWorkApp", count + " jobs imported!", Browser.Buttons.OK);

    function geocodeAddress(address) {
    var geocoder = Maps.newGeocoder();
    try {
    var geoJSON = geocoder.geocode(address);
    return geoJSON.results[0].geometry.location;
    } catch(e) {
    Logger.log("Geocoding Failed: Address is " + address);
    return { lat: '', lng: '' };
    }
    }
    };


    // ------
    // General util
    // ------
    String.prototype.trim = function() {
    return this.replace(/^\s+|\s+$/g,"");
    }


    // ------
    // vWorkApp API Class
    // ------

    vWorkAppAPI = function() {

    this.posthttp = function(url, payload) {
    Logger.log(JSON.stringify(payload));

    var advancedArgs = {
    method: "post",
    payload: JSON.stringify(payload),
    contentType: "application/json; charset=UTF-8"
    };

    Logger.log("Creating Job. Response was:" + UrlFetchApp.fetch(url, advancedArgs));
    };

    };

    vWorkAppAPI.prototype = {

    // --
    // Creates a job in vWorkApp.
    //
    //
    createJob: function(customerName, templateName, duration, steps, custom_fields) {
    var payload = {
    job: {
    customer_name: customerName,
    template_name: templateName,
    planned_duration: duration,
    steps: steps,
    custom_fields: custom_fields
    }
    };

    var url = "https://" + host + "/2.0/jobs?api_key=" + apiToken;
    this.posthttp(url, payload);

    }

    }