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:
- https://github.com/folio-org/ui-erm-usage/blob/master/src/components/ReportUpload/FileUploader.js
- https://github.com/folio-org/ui-data-import/tree/master/src/components/ImportJobs/components/FileUploader
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 |
---|---|---|---|---|
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 |
---|---|---|---|---|
data | string | NA | Yes | Base64 encoded file data |
document
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 |
---|---|---|---|---|
documents | array<document_metadata> | NA | Yes | Collection of document metadata records (no data) |
Business Logic
mod-invoice API:
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 |
---|---|---|---|---|---|
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) |
---|---|---|
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 |
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.
- - UINV-15Getting issue details... STATUS
- - STCOM-438Getting issue details... STATUS
- - UXPROD-720Getting issue details... STATUS
- - ERM-184Getting issue details... STATUS
- - MODINVOSTO-34Getting issue details... STATUS
- - MODINVOICE-81Getting issue details... STATUS
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.