The Consonance GraphQL API
  • Getting started
  • Bibliographic
    • Select filtered products and their work
    • Select works and their products
    • Select products filtered by price and format
    • Select products filtered by work attributes
    • Select works and their relevant marketing material
    • Sample AI/Tip Sheet
  • Production
    • Select works and their product production run details
    • Sample production request form
  • Legal
    • Select contract details
    • Select contract financial information
    • Select contract dates and rights
  • People
    • Select basic person details
    • Select person contact details
    • Select professional details
    • Select person details and contributing works
    • Select organisation details
  • Data exchange
    • Sample custom report sheet
    • Sample dashboard
Powered by GitBook
On this page
  1. Production

Sample production request form

Generate a production request form for a particular product using Google Docs

Explanation

Using a combination of GraphQL and Javascript in Google Docs and Apps Script you can populate fields for a production request form using fields that retrieve Work and Product level information. Note that some of these fields will require a production run to exist in Consonance in order to populate.

Setting Up the Sidebar in Google Docs:

  • Open a new Google Docs document.

  • Navigate to Extensions > Apps Script.

  • In the Apps Script Editor, click the plus icon (+) next to "Files" and create a new HTML file named 'sidebar'.

  • Copy and paste the HTML code below to create an interactive sidebar, replacing any placeholder text that already exists in the new file. This sidebar, accessible from the main navigation of your document, includes a form for inputting an ISBN, URL, and API key. The sidebar can be customised with CSS.

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
        <!--link href='https://fonts.googleapis.com/css?family=Open+Sans:400,600,300' rel='stylesheet' type='text/css'-->
    <link href='open-sans.css' rel='stylesheet' type='text/css'>
    <style type="text/css">
        * {
            font-family: 'Open Sans';
            font-style: normal;
            font-size: 13px;
        }
        .light { 
            font-weight: 300;
        }
        .regular { 
            font-weight: 400;
        }
        .semibold { 
            font-weight: 600;
        }
    </style>
  </head>
  <body>
    <p>
      Please type in the URL, Key, and ISBN13 that you want, and choose Find.
    <ul>
      <li>URL is usually https://web.consonance.app</li>
      <li>Key will be your API that you get by emailing support@consonance.app</li>
      <li>ISBN is something like 9781905005123</li>
    </ul>
    </p>
    <form id="isbnGetter">
      <p class="semibold">
        <label>Consonance URL</label>
        <br />
        <input type="text" value="https://web.consonance.app" id="url" name="url">
      </p>
      <p class="semibold">
        <label>Key</label>
        <br/>
        <input type="text" value="" id="key" name="key">
      </p>
      <p class="semibold">
        <label>ISBN</label>
        <br/>
        <input type="text" value="" id="isbn13" name="isbn13">
       </p>
      <input type="button" value="Find" onclick="google.script.run.main(isbnGetter)">
    </form>
  </body>
</html>

Creating the Main Script:

  • In the Script Editor, select Code.gs from the file section. Google might have called it something else, but there will only be one file with the .gs extension, so that's the one to select.

  • Copy and paste the JavaScript code below into this file. This code includes functions for opening the sidebar, sending GraphQL queries, and populating your Google Doc with the fetched data.

  • Optionally, replace placeholders like YOUR_API_KEY with actual values provided by Consonance support.

function onOpen() {
  DocumentApp.getUi()
    .createMenu('Consonance')
    .addItem('Show sidebar', 'showSidebar')
    .addToUi();
}

function showSidebar() {
  const html = HtmlService.createHtmlOutputFromFile('sidebar')
    .setTitle('Choose product');
  DocumentApp.getUi()
    .showSidebar(html)
}

function queryResponse(isbn, key, url) {
  const queryString = `
    query {
      product(productSearch: {isbn13Eq: "${isbn}"}) {
        id
        fullTitle
        subtitle
        publicationDate
        publicationDateString: publicationDateString(directives: "%B %Y")
        plannedPublicationDate
        isbn {isbn10 isbn13 isbnWithDashes}
        gbp_consumer_price: prices(priceSearch:{currencyCodeIn: [GBP], onixPriceTypeCodeIn: [_02], onixPriceTypeQualifierCodeIn: [_05]}) {
          amount
        }
      onix21ProductForm{ code description notes isDeprecated}
      onix21ProductFormCode
        inHouseEdition{
          name
          code
          inHouseFormats {code}
        }
        ... on PhysicalBookProduct {
                productHeightMm: productHeight
                productWidthMm: productWidth
                productHeightCm: productHeight(unit: CM)
                productWidthCm: productWidth(unit: CM)
                productHeightIn: productHeight(unit: IN)
                productWidthIn: productWidth(unit: IN)
                productThickness: productThickness(unit: MM)
                approximatePageCount
                productionPageCount
                mainContentPageCount
                frontMatterPageCount
                backMatterPageCount
                totalNumberedPages
                contentPageCount
                totalUnnumberedInsertPageCount
                wordCount
              }
        work {
          contributorPrettyList
          editionNumber
          imprint {
          id 
          name
          }
productionRuns {
        id
        name
        deliveryDate
        quantities {
          id
          name
          description
          quantity
          receivedQuantity
          productId
        }
        bindings {
          id
          widthOfBoard
          pageBindingMethod
          trimmingMethod
          endpapers
          caseSpineStyle
          description
          bindingInstructions
          productIds
          products {
            id
          }
        }
        covers {
          id
          paper
          coverType
          coverColoursOutside
          coverColoursOutsideDescription
          coverNotes
          productIds
          products {
            id
          }
        }
        embellishments {
          id
          name
          description
          productIds
          products {
            id
          }
        }
        finishes {
          id
          name
          description
          productIds
          products {
            id
          }
        }
        interiors {
          id
          paper
          textColour
          textColourDescription
          textPrintInstructions
          fsc
          productIds
          products {
            id
          }
        }
      }


          mainBicCode: subjectCodes(schemesIn: [BIC], mainOnly: true) {
         code
         description
        }
          mainThema: subjectCodes(schemesIn: [THEMA], mainOnly: true) {
            code
            description
           ... on Thema {
            parentCode
            }
          }
          mainBisac: subjectCodes(schemesIn: [BISAC], mainOnly: true) {
            code
            description
          }
        }
      }
    }
  ` 
  const payload = JSON.stringify({query: queryString})
  const response = UrlFetchApp.fetch(`${url}/graphql`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      authorization: `Bearer ${key}`,
    },
    payload: payload,
  });
  const stringResponse = response.getContentText()
  return JSON.parse(stringResponse)
}
// This sets default values if "form" is not there - i.e. if you're running this from the script editor
const main = (form = {isbn13:"YOUR_ISBN", key:"YOUR_API_KEY", url:"https://web.consonance.app"}) => {
  const doc = DocumentApp.getActiveDocument()
  const body = doc.getBody();
  const product = queryResponse(form.isbn13, form.key, form.url).data.product
  // Looks for a YYYY-MM-DD date pattern and replaces with today's date
  const today = Utilities.formatDate(new Date(), "GMT", "yyyy-MM-dd");
  const pattern = "\\d{2,4}-\\d{1,2}-\\d{1,2}";
  const todayDate = DocumentApp.getActiveDocument().getBody();
  body.editAsText().replaceText(pattern, today);

  body.replaceText("^.*QUOTEREF_*$", product.id || "-");
  body.replaceText("^.*ISBN13_*$", product.isbn.isbnWithDashes || "-");
  body.replaceText("^.*PUBDATE_*$", product.publicationDateString || "-");
  body.replaceText("^.*PUBDATE_*$", product.publicationDateString || "-");
  body.replaceText("^.*JOBNO_*$", product.work.productionRuns[0]?.id || "-");
  body.replaceText("^.*IMPRINTNAME_*$", product.work.imprint.name || "-");
  body.replaceText("^.*GBPRRP_*$", product.gbp_consumer_price[0]?.amount || "-");
  body.replaceText("^.*FORMATTYPE_*$", product.onix21ProductForm.description || "-");
  body.replaceText("^.*TRIMSIZE_*$", product.work.productionRuns[0]?.bindings[0]?.trimmingMethod || "-");
  body.replaceText("^.*BINDINGTYPE_*$", product.work.productionRuns[0]?.bindings[0]?.description || "-");
  body.replaceText("^.*PAGEEXTENT_*", product.productionPageCount || "-");
  body.replaceText("^.*PLATEEXT_*", product.totalUnnumberedInsertPageCount || "-");
  body.replaceText("^.*PLATEPOS_*", product.work.productionRuns[0]?.bindings[0]?.endpapers || "-");
  body.replaceText("^.*SPINEWIDTH_*", product.work.productionRuns[0]?.bindings[0]?.caseSpineStyle || "-");
  body.replaceText("^.*BOARDWIDTH_*", product.work.productionRuns[0]?.bindings[0]?.widthOfBoard || "-");
  body.replaceText("^.*TEXTCOL_*", product.work.productionRuns[0]?.interiors[0]?.textColour || "-");
  body.replaceText("^.*SECTCOL_*", product.work.productionRuns[0]?.interiors[0]?.textColourDescription || "-");
  body.replaceText("^.*SECTCOVER_*", product.work.productionRuns[0]?.covers[0]?.coverType || "-");
  body.replaceText("^.*PRINTFINISH_*", product.work.productionRuns[0]?.finishes[0]?.description || "-");
  body.replaceText("^.*TEXTPAPER_*", product.work.productionRuns[0]?.interiors[0]?.paper || "-");
  body.replaceText("^.*SECTPAPER_*", product.work.productionRuns[0]?.interiors[0]?.paper || "-");
  body.replaceText("^.*JACKETMAT_*", product.work.productionRuns[0]?.covers[0]?.paper || "-");
  body.replaceText("^.*CLOTHCOL_*", product.work.productionRuns[0]?.covers[0]?.coverColoursOutside || "-");
  body.replaceText("^.*ENDPAPERMAT_*", product.work.productionRuns[0]?.bindings[0]?.endpapers || "-");
  body.replaceText("^.*MATEXTRAS_*", product.work.productionRuns[0]?.embellishments[0]?.description || "-");
  body.replaceText("^.*EXPDELIVERY_*", product.plannedPublicationDate || "-");
  body.replaceText("^.*DELQUANTITY_*", product.work.productionRuns[0]?.quantities[0]?.receivedQuantity || "-");
}


Save the file. The top of the page should look like this, with onOpen selected:

Creating a template:

Type and format words as you'd usually do into the doc (not the script). The words that can be swapped out using the example we've given here are the ones in red in this screenshot:

e.g. type IMPRINTNAME_ into your doc to have it replaced with the imprint's name.

You can edit the script if you prefer different names, and add other queries.

Using Your Custom Production Request Form:

  • Back in your Google Docs document, a new menu item "Consonance" will appear in the main navigation bar.

  • Click on it and select the option to open the sidebar.

  • Fill out the form in the sidebar with the required information (URL, API Key, ISBN) and click "Find" to auto-populate the production request form.

Here is an example of how your Google doc might look before the script runs.

This is how it might look after choosing the 'Find' button.

Troubleshooting

If you are signed in to more than one Google account, this can apparently mess things up, so try signing out of all but one account if the Find button doesn't change anything.

You'll probably be prompted to authenticate: click OK on dialogue boxes that prompt you.

Raise a support ticket to get your API key at support@consonance.app.

Raise a ticket if you'd like us to share a starter template with you.

PreviousSelect works and their product production run detailsNextLegal

Last updated 1 year ago

Google Docs screenshot. The document has the heading Consonance Production Request Form and has many fields that are unpopulated.
Google Docs screenshot. The previously unpopulated fields now have relevant information retrieved from Consonance.