Split Attachment column into Invoice and Receipt fields
- Add separate Invoice and Receipt columns to Bills table for clearer document organization - Update upload-attachment.sh to accept column parameter (defaults to Invoice, use Receipt for payment confirmations) - Update all documentation examples and workflows - Add receipt upload step to payment workflows - Update validation checklist to verify both fields 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
46
SKILL.md
46
SKILL.md
@@ -78,7 +78,8 @@ Python: `int(datetime(2025, 10, 1).timestamp())`
|
|||||||
| Status | Choice | "Open", "Partial", "Paid" |
|
| Status | Choice | "Open", "Partial", "Paid" |
|
||||||
| Memo | Text | |
|
| Memo | Text | |
|
||||||
| EntryTransaction | Ref:Transactions | Link to journal entry |
|
| EntryTransaction | Ref:Transactions | Link to journal entry |
|
||||||
| Attachment | Attachments | Invoice/receipt files (use `["L", id]` format) |
|
| Invoice | Attachments | Vendor invoice document (use `["L", id]` format) |
|
||||||
|
| Receipt | Attachments | Payment receipt/confirmation (use `["L", id]` format) |
|
||||||
| Amount | Formula | Sum of BillLines.Amount |
|
| Amount | Formula | Sum of BillLines.Amount |
|
||||||
| AmountPaid | Formula | Sum of BillPayments.Amount |
|
| AmountPaid | Formula | Sum of BillPayments.Amount |
|
||||||
| AmountDue | Formula | Amount - AmountPaid |
|
| AmountDue | Formula | Amount - AmountPaid |
|
||||||
@@ -219,12 +220,12 @@ add_records("TransactionLines", [
|
|||||||
update_records("Bills", [{"id": 1, "fields": {"EntryTransaction": 1}}])
|
update_records("Bills", [{"id": 1, "fields": {"EntryTransaction": 1}}])
|
||||||
```
|
```
|
||||||
|
|
||||||
**Step 5: Upload Invoice Attachment (if available)**
|
**Step 5: Upload Invoice (if available)**
|
||||||
|
|
||||||
If an invoice PDF is available, upload and link it:
|
If an invoice PDF is available, upload and link it to the Invoice field:
|
||||||
```bash
|
```bash
|
||||||
# Get session token, then upload
|
# Get session token, then upload to Invoice field
|
||||||
./scripts/upload-attachment.sh invoice.pdf Bills 1 $TOKEN
|
bash /path/to/scripts/upload-attachment.sh invoice.pdf Bills 1 $TOKEN Invoice
|
||||||
```
|
```
|
||||||
|
|
||||||
Or for batch uploads, use a script (see Batch Operations).
|
Or for batch uploads, use a script (see Batch Operations).
|
||||||
@@ -257,6 +258,9 @@ add_records("BillPayments", [{
|
|||||||
|
|
||||||
# Step 4: Update bill status
|
# Step 4: Update bill status
|
||||||
update_records("Bills", [{"id": 1, "fields": {"Status": "Paid"}}])
|
update_records("Bills", [{"id": 1, "fields": {"Status": "Paid"}}])
|
||||||
|
|
||||||
|
# Step 5: Upload receipt (if available)
|
||||||
|
bash /path/to/scripts/upload-attachment.sh receipt.pdf Bills 1 $TOKEN Receipt
|
||||||
```
|
```
|
||||||
|
|
||||||
### Pay Bill via Owner Reimbursement
|
### Pay Bill via Owner Reimbursement
|
||||||
@@ -288,6 +292,9 @@ add_records("BillPayments", [{
|
|||||||
|
|
||||||
# Step 4: Update bill status
|
# Step 4: Update bill status
|
||||||
update_records("Bills", [{"id": 1, "fields": {"Status": "Paid"}}])
|
update_records("Bills", [{"id": 1, "fields": {"Status": "Paid"}}])
|
||||||
|
|
||||||
|
# Step 5: Upload receipt (if available)
|
||||||
|
bash /path/to/scripts/upload-attachment.sh receipt.pdf Bills 1 $TOKEN Receipt
|
||||||
```
|
```
|
||||||
|
|
||||||
### Reimburse Owner
|
### Reimburse Owner
|
||||||
@@ -329,14 +336,17 @@ When invoice files are available, upload them after bill entry:
|
|||||||
3. Loop: upload each file, link to corresponding bill
|
3. Loop: upload each file, link to corresponding bill
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Example batch upload pattern
|
# Example batch upload pattern for invoices
|
||||||
TOKEN=$(request_session_token with write permission)
|
TOKEN=$(request_session_token with write permission)
|
||||||
for each (bill_id, invoice_path):
|
for each (bill_id, invoice_path):
|
||||||
curl -X POST -H "Authorization: Bearer $TOKEN" \
|
curl -X POST -H "Authorization: Bearer $TOKEN" \
|
||||||
-F "file=@$invoice_path" \
|
-F "file=@$invoice_path" \
|
||||||
https://grist-mcp.bballou.com/api/v1/attachments
|
https://grist-mcp.bballou.com/api/v1/attachments
|
||||||
# Returns attachment_id
|
# Returns attachment_id
|
||||||
update_records("Bills", [{"id": bill_id, "fields": {"Attachment": ["L", attachment_id]}}])
|
update_records("Bills", [{"id": bill_id, "fields": {"Invoice": ["L", attachment_id]}}])
|
||||||
|
|
||||||
|
# For receipts (after payment):
|
||||||
|
update_records("Bills", [{"id": bill_id, "fields": {"Receipt": ["L", attachment_id]}}])
|
||||||
```
|
```
|
||||||
|
|
||||||
Example batch update:
|
Example batch update:
|
||||||
@@ -529,7 +539,8 @@ After entering bills, verify:
|
|||||||
- [ ] AP balance correct: `SELECT Balance FROM Accounts WHERE Code = '2000'`
|
- [ ] AP balance correct: `SELECT Balance FROM Accounts WHERE Code = '2000'`
|
||||||
- [ ] Expense accounts increased appropriately
|
- [ ] Expense accounts increased appropriately
|
||||||
- [ ] Vendor balances reflect unpaid bills
|
- [ ] Vendor balances reflect unpaid bills
|
||||||
- [ ] Invoice attachments linked: `SELECT id, BillNumber FROM Bills WHERE Attachment IS NULL`
|
- [ ] Invoices attached: `SELECT id, BillNumber FROM Bills WHERE Invoice IS NULL`
|
||||||
|
- [ ] Receipts attached for paid bills: `SELECT id, BillNumber FROM Bills WHERE Status = 'Paid' AND Receipt IS NULL`
|
||||||
|
|
||||||
## Common Mistakes
|
## Common Mistakes
|
||||||
|
|
||||||
@@ -542,7 +553,7 @@ After entering bills, verify:
|
|||||||
| Missing EntryTransaction link | Always update Bill.EntryTransaction after creating journal entry |
|
| Missing EntryTransaction link | Always update Bill.EntryTransaction after creating journal entry |
|
||||||
| Bill status not updated | Manually set Status to "Paid" after full payment |
|
| Bill status not updated | Manually set Status to "Paid" after full payment |
|
||||||
| Using string dates | Dates must be Unix timestamps (seconds), not strings |
|
| Using string dates | Dates must be Unix timestamps (seconds), not strings |
|
||||||
| Missing invoice attachments | Upload invoices after bill entry if files available |
|
| Missing invoice/receipt | Upload invoice after bill entry, receipt after payment |
|
||||||
|
|
||||||
## Uploading Attachments
|
## Uploading Attachments
|
||||||
|
|
||||||
@@ -561,23 +572,26 @@ Use `scripts/upload-attachment.sh` in this skill directory:
|
|||||||
```bash
|
```bash
|
||||||
# Get session token first (via MCP request_session_token tool)
|
# Get session token first (via MCP request_session_token tool)
|
||||||
# Then run:
|
# Then run:
|
||||||
./scripts/upload-attachment.sh invoice.pdf Bills 13
|
bash scripts/upload-attachment.sh invoice.pdf Bills 13 # Invoice column (default)
|
||||||
|
bash scripts/upload-attachment.sh invoice.pdf Bills 13 $TOKEN # With token
|
||||||
# Or pass token directly:
|
bash scripts/upload-attachment.sh receipt.pdf Bills 13 $TOKEN Receipt # Receipt column
|
||||||
./scripts/upload-attachment.sh invoice.pdf Bills 13 sess_abc123...
|
|
||||||
|
|
||||||
# Environment variable for custom endpoint:
|
# Environment variable for custom endpoint:
|
||||||
GRIST_MCP_URL=https://custom.example.com ./scripts/upload-attachment.sh ...
|
GRIST_MCP_URL=https://custom.example.com bash scripts/upload-attachment.sh ...
|
||||||
```
|
```
|
||||||
|
|
||||||
Run `./scripts/upload-attachment.sh` without arguments for full usage.
|
Run `bash scripts/upload-attachment.sh` without arguments for full usage.
|
||||||
|
|
||||||
### Linking Attachments Manually
|
### Linking Attachments Manually
|
||||||
|
|
||||||
Grist attachment columns use format: `["L", attachment_id]`
|
Grist attachment columns use format: `["L", attachment_id]`
|
||||||
|
|
||||||
```python
|
```python
|
||||||
update_records("Bills", [{"id": 13, "fields": {"Attachment": ["L", 1]}}])
|
# Link invoice to bill
|
||||||
|
update_records("Bills", [{"id": 13, "fields": {"Invoice": ["L", 1]}}])
|
||||||
|
|
||||||
|
# Link receipt to bill (after payment)
|
||||||
|
update_records("Bills", [{"id": 13, "fields": {"Receipt": ["L", 2]}}])
|
||||||
```
|
```
|
||||||
|
|
||||||
## Formula Columns (Auto-Calculated)
|
## Formula Columns (Auto-Calculated)
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# upload-attachment.sh - Upload file and link to Grist record
|
# upload-attachment.sh - Upload file and link to Grist record
|
||||||
# Usage: ./upload-attachment.sh <file> <table> <record_id> [token]
|
# Usage: ./upload-attachment.sh <file> <table> <record_id> [token] [column]
|
||||||
#
|
#
|
||||||
# Examples:
|
# Examples:
|
||||||
# ./upload-attachment.sh invoice.pdf Bills 13
|
# ./upload-attachment.sh invoice.pdf Bills 13 # defaults to Invoice column
|
||||||
# ./upload-attachment.sh receipt.jpg Bills 13 sess_abc123...
|
# ./upload-attachment.sh invoice.pdf Bills 13 sess_abc123... # with token
|
||||||
|
# ./upload-attachment.sh receipt.pdf Bills 13 sess_abc123... Receipt # specify column
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
@@ -12,17 +13,21 @@ FILE="$1"
|
|||||||
TABLE="$2"
|
TABLE="$2"
|
||||||
RECORD_ID="$3"
|
RECORD_ID="$3"
|
||||||
TOKEN="$4"
|
TOKEN="$4"
|
||||||
|
COLUMN="${5:-Invoice}" # Default to Invoice column
|
||||||
|
|
||||||
if [[ -z "$FILE" || -z "$TABLE" || -z "$RECORD_ID" ]]; then
|
if [[ -z "$FILE" || -z "$TABLE" || -z "$RECORD_ID" ]]; then
|
||||||
echo "Usage: $0 <file> <table> <record_id> [token]"
|
echo "Usage: $0 <file> <table> <record_id> [token] [column]"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Arguments:"
|
echo "Arguments:"
|
||||||
echo " file Path to file to upload"
|
echo " file Path to file to upload"
|
||||||
echo " table Grist table name (e.g., Bills)"
|
echo " table Grist table name (e.g., Bills)"
|
||||||
echo " record_id Record ID to attach file to"
|
echo " record_id Record ID to attach file to"
|
||||||
echo " token Session token (optional, will prompt if not provided)"
|
echo " token Session token (optional, will prompt if not provided)"
|
||||||
|
echo " column Attachment column name (default: Invoice, use Receipt for payment receipts)"
|
||||||
echo ""
|
echo ""
|
||||||
echo "Example: $0 invoice.pdf Bills 13"
|
echo "Examples:"
|
||||||
|
echo " $0 invoice.pdf Bills 13 # Upload invoice"
|
||||||
|
echo " $0 receipt.pdf Bills 13 \$TOKEN Receipt # Upload receipt"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -53,12 +58,12 @@ fi
|
|||||||
echo "Uploaded: attachment_id=$ATTACHMENT_ID"
|
echo "Uploaded: attachment_id=$ATTACHMENT_ID"
|
||||||
|
|
||||||
# Link to record via proxy
|
# Link to record via proxy
|
||||||
echo "Linking to $TABLE id=$RECORD_ID..."
|
echo "Linking to $TABLE id=$RECORD_ID column=$COLUMN..."
|
||||||
LINK_RESPONSE=$(curl -s -X POST \
|
LINK_RESPONSE=$(curl -s -X POST \
|
||||||
-H "Authorization: Bearer $TOKEN" \
|
-H "Authorization: Bearer $TOKEN" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d "{\"method\": \"update_records\", \"table\": \"$TABLE\", \"records\": [{\"id\": $RECORD_ID, \"fields\": {\"Attachment\": [\"L\", $ATTACHMENT_ID]}}]}" \
|
-d "{\"method\": \"update_records\", \"table\": \"$TABLE\", \"records\": [{\"id\": $RECORD_ID, \"fields\": {\"$COLUMN\": [\"L\", $ATTACHMENT_ID]}}]}" \
|
||||||
"$BASE_URL/api/v1/proxy")
|
"$BASE_URL/api/v1/proxy")
|
||||||
|
|
||||||
echo "$LINK_RESPONSE" | jq .
|
echo "$LINK_RESPONSE" | jq .
|
||||||
echo "Done! Attachment $ATTACHMENT_ID linked to $TABLE record $RECORD_ID"
|
echo "Done! Attachment $ATTACHMENT_ID linked to $TABLE.$COLUMN record $RECORD_ID"
|
||||||
|
|||||||
Reference in New Issue
Block a user