Attaching Documents to Invoices

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

Property

Type

Default

Required

Notes

Property

Type

Default

Required

Notes

name

string

NA

Yes

The original document name for display purposes (filename or link "nickname")

invoiceId

string

NA

Yes

UUID of the invoice the document is attached to

url

string

NA

No

URL pointing to the document - restrict with regex pattern

metadata

metadata

NA

No

System generated record metadata

document_data

Property

Type

Default

Required

Notes

Property

Type

Default

Required

Notes

data

string

NA

Yes

Base64 encoded file data

document

Property

Type

Default

Required

Notes

Property

Type

Default

Required

Notes

id

string

NA

No

UUID - system generated if not specified

documentMetadata

document_metadata

NA

Yes

Document metadata

contents

document_data

NA

No

Base64 encoded file data

document_collection

Property

Type

Default

Required

Notes

Property

Type

Default

Required

Notes

documents

array<document_metadata>

NA

Yes

Collection of document metadata records (no data)

Business Logic

mod-invoice API:

Method

Endpoint

Request

Response

Description

Notes

Method

Endpoint

Request

Response

Description

Notes

POST

/invoice/invoices/<invoiceId>/documents

document

document

Upload an invoice document

proxies to corresponding storage endpoint

GET

/invoice/invoices/<invoiceId>/documents

CQL Query Arg

document_collection

Search/List invoice documents (w/o data)

proxies to corresponding storage endpoint

GET

/invoice/invoices/<invoiceId>/documents/<id>

NA

document

Get a specific invoice document (w/ data)

proxies to corresponding storage endpoint

DELETE

/invoice/invoices/<invoiceId>/documents/<id>

NA

204

Delete a specific invoice document

proxies to corresponding storage endpoint

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

Storage

mod-invoice-storage API:

Method

Endpoint

Request

Response

Description

Notes

Method

Endpoint

Request

Response

Description

Notes

POST

/invoice-storage/invoices/<invoiceId>/documents

document

document

Upload an invoice document

 

GET

/invoice-storage/invoices/<invoiceId>/documents

CQL Query Arg

document_collection

Search/List invoice documents

data not included

GET

/invoice-storage/invoices/<invoiceId>/documents/<id>

NA

document

Get a specific invoice document

data included

DELETE

/invoice-storage/invoices/<invoiceId>/documents/<id>

NA

204

Delete 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)

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.