Attaching Documents to Invoices

Overview

A requirement exists for the ability to attach/associate documents with an invoice, either via a hyperlink to the document or by direct upload and storage within FOLIO.  

User Interface

Stripes components have been developed using react-dropzone.  We can probably reuse/borrow from these:

When a file is selected or dragged/dropped into this component, ui-invoice would read the file, base64 encode it and send the data along with some metadata to the mod-invoice documents API.

When a document is linked to the invoice, ui-invoice would still use the same API, only instead of supplying file data, just document_metadata will be populated, including a link (url) to the document.

Schemas

document_metadata

PropertyTypeDefaultRequiredNotes
name
string
NAYesThe original document name for display purposes (filename or link "nickname")
invoiceId
string
NAYesUUID of the invoice the document is attached to
url
string
NANoURL pointing to the document - restrict with regex pattern
metadata
metadata
NANoSystem generated record metadata

document_data

PropertyTypeDefaultRequiredNotes
data
string
NAYesBase64 encoded file data

document

PropertyTypeDefaultRequiredNotes
id
string
NANoUUID - system generated if not specified
documentMetadata
document_metadata
NAYesDocument metadata
contents
document_data
NANoBase64 encoded file data

document_collection

PropertyTypeDefaultRequiredNotes
documents
array<document_metadata>
NAYesCollection of document metadata records (no data)

Business Logic

mod-invoice API:

MethodEndpointRequestResponseDescriptionNotes
POST
/invoice/invoices/<invoiceId>/documents
documentdocumentUpload an invoice documentproxies to corresponding storage endpoint
GET
/invoice/invoices/<invoiceId>/documents
CQL Query Argdocument_collectionSearch/List invoice documents (w/o data)proxies to corresponding storage endpoint
GET
/invoice/invoices/<invoiceId>/documents/<id>
NAdocumentGet a specific invoice document (w/ data)proxies to corresponding storage endpoint
DELETE
/invoice/invoices/<invoiceId>/documents/<id>
NA204Delete a specific invoice documentproxies to corresponding storage endpoint

NOTE:  PUT omitted intentionally - for simplicity, documents are immutable.

Storage

mod-invoice-storage API:

MethodEndpointRequestResponseDescriptionNotes
POST
/invoice-storage/invoices/<invoiceId>/documents
documentdocumentUpload an invoice document
GET
/invoice-storage/invoices/<invoiceId>/documents
CQL Query Argdocument_collectionSearch/List invoice documentsdata not included
GET
/invoice-storage/invoices/<invoiceId>/documents/<id>
NAdocumentGet a specific invoice documentdata included
DELETE
/invoice-storage/invoices/<invoiceId>/documents/<id>
NA204Delete a specific invoice document

NOTE:  PUT omitted intentionally - for simplicity, documents are immutable.

Database Model

The underlying "documents" table looks something like:

id (uuid)document_metadata (jsonb)document_data (text)
412e145e-3a47-4993-9ffa-54552d8fcf66
{
  "name": "inv002.pdf",
  "invoiceId": "ed0053e2-c4f2-4b98-9b87-33430071f8fe",
  "metadata": {
    "createdDate": "2019-07-08T19:29:38.001+0000",
    "updatedDate": "2019-07-08T19:29:38.001+0000",
    "createdByUserId": "ef676db9-d231-479a-aa91-f65eb4b17872",
    "updatedByUserId": "ef676db9-d231-479a-aa91-f65eb4b17872"
  }
}
data:application/pdf;base64,T3ZlcnZpZXcKQS
gc2V2ZXJhbCBGT0xJTyBhcHBzIHRvIGJlIGFibGUgd
G8gc3RvcmUgZmlsZXMuduIHNICBJbnN0ZWFkIG9mIG
hY2ggb2YgdGhvc2UgYXBwcyduIHNBpbXBsZW1lbnRp
mcgdGhlaXIgb3duIHNvbHV0aW9uLCBpdCBwcm9duIH
iYWJseSBtYWtlcduIHNyBzZW5zZSB0byBjcmVhdGUg
udHJhbGl6ZWQgZduIHNmlsZSBzdG9yYWdlIGZhY2ls
JlIHF1aXRlIGxhcmdlCk11c3QgYmUgYWJsZSB0b...
eba3931d-3151-496c-ba2a-6a409c7b63a3
{
  "name": "inv003.pdf",
  "invoiceId": "ed0053e2-c4f2-4b98-9b87-33430071f8fe",
  "url": "s3://diku.file-storage.us-east-1/invoices/inv003.pdf",
  "metadata": {
    "createdDate": "2019-07-08T19:29:38.001+0000",
    "updatedDate": "2019-07-08T19:29:38.001+0000",
    "createdByUserId": "ef676db9-d231-479a-aa91-f65eb4b17872",
    "updatedByUserId": "ef676db9-d231-479a-aa91-f65eb4b17872"
  }
}

JIRA

A convenient place to put links to relevant JIRA epics/features/stories/bugs/etc.

Open Issues/Considerations

  • Right now the relation is from document → invoice, but it might makes more sense to have invoice → documents (even if it's an array of IDs)
  • It may be possible to store the data in SRS (source record storage), though at the moment it looks as though only MARC files are supported.
    •  CAM - I asked FOLIJET about this and it seems generic file storage is not supported at this time. 
  • Documents will for the most part be PDFs under 100KB in size (often under 50KB).  These are typically scanned documents comprised mainly of text w/ annotations.