Import From Paperless

Summary: Imports a database from the Mariner Paperless app (formerly ReceiptWallet).
Requires: EagleFiler
Install Location: ~/Library/Scripts/Applications/EagleFiler/
Last Modified: 2026-01-14

Description

The Paperless app from Mariner Software (formerly called ReceiptWallet) has been discontinued. This script lets you migrate the files and metadata from your Paperless database into EagleFiler. When you run the script, it will ask you to select the .paperless package for your database. It will then import all the files into the frontmost EagleFiler library window:

Installation Instructions · Download in Compiled Format · Download in Text Format

Script

use AppleScript version "2.4"
use
framework "Foundation"
use
scripting additions

set
_package to choose file of type {"paperless"} with prompt "Select the Mariner Paperless package to import into EagleFiler."
set
_databasePath to _package's POSIX path & "/DocumentWallet.documentwalletsql"
my
importPackage(_package)

on
importPackage(_package)
    set
_folderName to my basename(_package's POSIX path)
    tell
application "EagleFiler"
        tell
library document 1
            set
_folderRecord to add folder name _folderName
        end tell
    end tell
    set
_ids to getDocumentIDs()
    repeat with
_id in _ids
        my
importID(_id, _folderRecord)
    end repeat
end
importPackage

on
getDocumentIDs()
    
paragraphs of my sqlite("SELECT Z_PK FROM ZRECEIPT ORDER BY Z_PK")
end
getDocumentIDs

on
importID(_id, _topFolderRecord)
    if my
isInTrash(_id) then
        set
_topFolderRecord to my getFolder(_topFolderRecord, "Trash")
    end if
    set
_category to my getCategoryName(_id)
    set
_subcategory to my getSubcategoryName(_id)
    set
_folderRecord to _topFolderRecord
    if
_category is not "" then
        set
_folderRecord to my getFolder(_topFolderRecord, _category)
    end if
    if
_subcategory is not "" then
        set
_folderRecord to my getFolder(_folderRecord, _subcategory)
    end if
    tell
application "EagleFiler"
        global
_package
        tell
_folderRecord's library document
            set
_path to _package's POSIX path & "/" & my getAttribute(_id, "ZPATH")
            try
                set {
_record} to import files {_path} container _folderRecord tag names my getTagNames(_id) note my getNote(_id) with allowing duplicates
                set
_record's added date to my getDate(_id, "ZIMPORTDATE")
                set
_record's creation date to my getDate(_id, "ZDATE")
                set
_record's from name to my getAttribute(_id, "ZMERCHANT")
            on error
_error
                with timeout of 60 * 60 * 24
seconds
                    
display dialog "Error importing: " & _path & return & return & _error
                end timeout
            end try
        end tell
    end tell
end
importID

on
isInTrash(_id)
    set
_value to my getAttribute(_id, "ZINTRASHVALUE")
    if
_value is "" then return false
    return
_value as number as boolean
end
isInTrash

on
getAttribute(_id, _name)
    my
sqlite("SELECT " & _name & " FROM ZRECEIPT WHERE Z_PK=" & _id)
end
getAttribute

on
getCategoryName(_id)
    my
sqlite("SELECT ZNAME FROM ZCATEGORY INNER JOIN ZRECEIPT ON ZCATEGORY.Z_PK = ZRECEIPT.ZCATEGORY WHERE ZRECEIPT.Z_PK=" & _id)
end
getCategoryName

on
getSubcategoryName(_id)
    my
sqlite("SELECT ZNAME FROM ZSUBCATEGORY INNER JOIN ZRECEIPT ON ZSUBCATEGORY.Z_PK = ZRECEIPT.ZSUBCATEGORY WHERE ZRECEIPT.Z_PK=" & _id)
end
getSubcategoryName

on
getDate(_id, _name)
    set
_timeInterval to my getAttribute(_id, _name) as number
    set
_nsDate to current application's NSDate's dateWithTimeIntervalSinceReferenceDate:_timeInterval
    return
_nsDate as date
end
getDate

on
getTagNames(_id)
    set
_sql to "SELECT ZNAME FROM ZTAG WHERE Z_PK IN (SELECT Z_18TAGS FROM Z_14TAGS INNER JOIN ZRECEIPT ON Z_14TAGS.Z_14RECEIPTS1 = ZRECEIPT.Z_PK WHERE ZRECEIPT.Z_PK=" & _id & ")"
    set
_tagNames to paragraphs of my sqlite(_sql)
    return
_tagNames
end
getTagNames

on
getNote(_id)
    set
_note to ""
    set
_note to my appendField(_note, "Amount", _id, "ZAMOUNTASSTRING")
    set
_note to my appendField(_note, "Shipping", _id, "ZSHIPPINGAMOUNTASSTRING")
    set
_note to my appendField(_note, "Shipping", _id, "ZSHIPPINGAMOUNTSTRING")
    set
_note to my appendField(_note, "Tax", _id, "ZTAXAMOUNT2ASSTRING")
    set
_note to my appendField(_note, "Tax", _id, "ZTAXAMOUNTASSTRING")
    set
_note to my appendField(_note, "Tax", _id, "ZTAXAMOUNTSTRING2")
    set
_note to my appendField(_note, "Tip", _id, "ZTIPAMOUNTASSTRING")
    set
_note to my appendField(_note, "Tip", _id, "ZTIPAMOUNTSTRING")
    set
_note to my appendField(_note, "Custom 1", _id, "ZCUSTOM1")
    set
_note to my appendField(_note, "Custom 2", _id, "ZCUSTOM2")
    set
_note to my appendField(_note, "Custom 3", _id, "ZCUSTOM3")
    set
_note to my appendField(_note, "Custom 4", _id, "ZCUSTOM4")
    set
_note to my appendField(_note, "Custom 5", _id, "ZCUSTOM5")
    set
_note to my appendField(_note, "Custom 6", _id, "ZCUSTOM6")
    set
_note to my appendField(_note, "Notes", _id, "ZNOTES")
    set
_note to my appendField(_note, "OCR", _id, "ZOCRRESULT")
end
getNote

on
appendField(_string, _title, _id, _column)
    set
_value to my getAttribute(_id, _column)
    if
_value is "" then return _string
    if
_value is "$0.00" and _column contains "AMOUNT" then return _string
    if
_title is not "" then
        set
_string to _string & _title & ": "
    end if
    set
_string to _string & _value
    set
_string to _string & return
    return
_string
end
appendField

on
sqlite(_sql)
    global
_databasePath
    set
_script to "sqlite3 " & _databasePath's quoted form & " " & _sql's quoted form
    
do shell script _script
end
sqlite

on
getFolder(_folderRecord, _name)
    tell
application "EagleFiler"
        set
_name to my makeFileNameValid(_name)
        try
            return
library record _name of _folderRecord
        on error
            tell
_folderRecord's library document
                return
add folder name _name container _folderRecord
            end tell
        end try
    end tell
end
getFolder

on
makeFileNameValid(_name)
    set
_name to my replace(_name, ":", ":") -- "FULLWIDTH COLON" U+FF1A
    set
_name to my replace(_name, "/", ":")
    set
_limit to 255
    set
_extension to my pathExtension(_name)
    set
_basename to my basename(_name)
    set
_basenameLimit to _limit - ((length of _extension) + 1)
    set
_basename to my prefix(_basename, _basenameLimit)
    if
_extension is "" then return _basename
    set
_result to _basename & "." & _extension
    set
_result to my replace(_name, ":", "/")
    return
_result
end
makeFileNameValid

on
basename(_path)
    set
_nsString to current application's NSString's stringWithString:_path
    return
_nsString's lastPathComponent's stringByDeletingPathExtension as Unicode text
end
basename

on
pathExtension(_path)
    set
_nsString to current application's NSString's stringWithString:_path
    return
_nsString's lastPathComponent's pathExtension as Unicode text
end
pathExtension

on
replace(_string, _source, _replacement)
    return my
join(my split(_string, _source), _replacement)
end
replace

on
join(_list, _sep)
    set
_temp to AppleScript's text item delimiters
    set
AppleScript's text item delimiters to _sep
    set
_result to _list as string
    set
AppleScript's text item delimiters to _temp
    return
_result
end
join

on
split(_string, _sep)
    set
_temp to AppleScript's text item delimiters
    set
AppleScript's text item delimiters to _sep
    set
_result to text items of _string
    set
AppleScript's text item delimiters to _temp
    return
_result
end
split

on
prefix(_string, _length)
    if
length of _string_length then return _string
    my
join(characters 1 thru _string of _basename, "")
end
prefix