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-15 - Getting issue details... STATUS
- STCOM-438 - Getting issue details... STATUS
- UXPROD-720 - Getting issue details... STATUS
- ERM-184 - Getting issue details... STATUS
- MODINVOSTO-34 - Getting issue details... STATUS
- MODINVOICE-81 - Getting 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.