Renamed in engine.ps1, both EXAMPLE configs, and the README. Existing entity.json/practice.json files using insurance_path keep working - the engine copies it to tiff_path after the merge when tiff_path isn't set.
Melissa Uploader
Automated upload tool for practice exports. Uploads insurance PDFs and patient files to the correct FTP/SFTP servers for each practice, then archives what was sent.
First-time setup
- Double-click setup.bat — this downloads WinSCP (needed for uploading)
- Set up your entity folders (see below)
- Double-click run-all.bat each day after running the PT STMT rename script
Daily workflow
- Run the PT STMT rename script manually (as usual)
- Double-click run-all.bat to upload everything
- Check the window for any failures — failed files stay in place for retry
Folder layout
run-all.bat <- double-click to run everything
engine.ps1
setup.bat
WinSCP\ <- created by setup.bat automatically
Entities\
CAMBS\
entity.json <- server details for this entity
run.bat <- double-click to run just CAMBS
Export1\
AJMAT\
practice.json <- only needed if AJMAT has its own FTP login
20260629\ <- today's insurance PDFs go here
Archive sent to FTP\ <- uploaded date folders move here
Patient\
Export\
PT STMT_20260629\ <- created by rename script
Archive Sent to FTP\ <- uploaded patient folders move here
CIIR\
...
CONSensio\
entity.json
...
The two config files
There are two JSON files, and they work together — one sets the defaults for the whole entity, the other overrides just what's different for one practice.
entity.json— lives in the entity folder (e.g.Entities\CAMBS\entity.json). Required. This is the default server info used by every practice under that entity: which server, which login, which folder paths.practice.json— lives inside one practice's folder (e.g.Entities\CAMBS\Export1\AJMAT\practice.json). Optional — only add it if a practice needs something different fromentity.json. Whatever fields you put in here replace the matching field fromentity.jsonfor that practice only; anything you leave out still comes fromentity.json.
Common reasons to add a practice.json:
- The practice has its own separate FTP/SFTP login instead of the shared one
- The practice's files need to go to a different folder path on the
server than the standard
{practice}pattern (e.g. the imaging vendor set it up with a different folder name, or a nonstandard structure) — overridetiff_path,pdf_path, and/orpatient_pathto whatever that practice actually needs
You can mix and match — e.g. override just pdf_path for one practice and
leave its login and every other path alone.
entity.json
- Create a folder under
Entities\with the entity name (e.g.Entities\CAMBS\) - Copy
run.batinto it - Create
entity.jsonin that folder — copy fromEntities\EXAMPLE\entity.jsonand fill in your real values. A complete file looks like this:
{
"workflow": "insurance+patient",
"insurance_file_type": "pdf",
"ftps": {
"host": "ftp.example.com",
"port": 21,
"tls": true,
"username": "shared-username",
"password": "shared-password",
"tiff_path": "/{practice}/Insurance",
"pdf_path": "/{practice}/PDF"
},
"sftp": {
"host": "sftp.example.com",
"port": 22,
"username": "shared-username",
"password": "shared-password",
"patient_path": "/{practice}/Patient"
}
}
| Setting | Required? | What to put |
|---|---|---|
workflow |
Yes | insurance if no patient files, insurance+patient if both |
insurance_file_type |
No (defaults to pdf) |
Set to tif for an entity whose imaging system exports the daily files as TIFs instead of PDFs (CAMBS, RMI, CONSENSIO, INLAND). Goes at the top level, next to workflow — NOT inside ftps |
ftps.host |
Yes | FTP server address |
ftps.port |
No (defaults to 21) | FTP port, only if not 21 |
ftps.tls |
Yes | true for FTPS (secure), false for plain FTP |
ftps.username |
Yes | FTP username (shared across all practices) |
ftps.password |
Yes | FTP password |
ftps.tiff_path |
Yes | Remote folder for insurance files — keep {practice} in it. (The older name insurance_path still works too) |
ftps.pdf_path |
Yes | Remote folder for PT STMT files — keep {practice} in it |
sftp.host |
Only if insurance+patient |
SFTP server address |
sftp.port |
No (defaults to 22) | SFTP port, only if not 22 |
sftp.username |
Only if insurance+patient |
SFTP username |
sftp.password |
Only if insurance+patient |
SFTP password |
sftp.patient_path |
Only if insurance+patient |
Remote folder for patient files — keep {practice} in it |
- Create the
Export1\folder and a subfolder for each practice inside the entity folder
{practice} in any path gets automatically replaced with that practice's
folder name — so one entity.json can serve every practice as long as they
all follow the same folder-naming pattern on the server.
Every "Yes" field must be present in entity.json unless every single
practice under the entity supplies it in its own practice.json. If a
required field is missing or blank, the run stops that practice with a
CONFIG ERROR message naming exactly which fields it couldn't find — nothing
uploads and nothing archives for that practice until it's fixed.
Editing JSON — the rules that bite:
- Key names must match exactly (all lowercase, underscores):
host, nothostname;username, notuser;tiff_path, nottiffpath - Every
"key": "value"pair ends with a comma except the last one in its block — a missing or extra comma breaks the whole file - Keep values inside straight double quotes (
"). Avoid editing in Word or anything that turns quotes curly — use Notepad portnumbers andtlstrue/false do not get quotes; everything else does
practice.json — overriding one practice
If one practice needs a different login, a different folder path, or both:
- Create a
practice.jsonfile inside that practice's folder (next to its date folders, e.g.Entities\CAMBS\Export1\AJMAT\practice.json) - Copy from
Entities\EXAMPLE\Export1\PRACTICE_NAME\practice.json - Delete every line you don't need to change — keep only the fields that
differ for this practice. Everything you delete falls back to
entity.json.
The field names are the same ones as entity.json, wrapped in the same
ftps / sftp sections. A practice.json can also add a field that
entity.json doesn't have at all — e.g. if entity.json has no
tiff_path because every practice's path is different, each practice's
practice.json can carry its own.
Example — this practice only has its own PDF folder name, nothing else differs:
{
"ftps": {
"pdf_path": "/{practice}/PDF_Statements_Custom"
}
}
Example — this practice has its own SFTP login but uses the same paths as everyone else:
{
"sftp": {
"username": "ajmat-sftp-user",
"password": "ajmat-sftp-pass"
}
}
Example — this practice has completely different remote folders for everything:
{
"ftps": {
"tiff_path": "/SpecialFolder/Claims",
"pdf_path": "/SpecialFolder/Statements"
},
"sftp": {
"patient_path": "/SpecialFolder/Patients"
}
}
Note: a practice.json never needs workflow or insurance_file_type —
those are entity-wide only.
Something went wrong?
- Files failed to upload — they stay in the date folder. Fix the issue and run again.
- A date folder is still there after running — one or more files failed. Check the output window.
- WinSCP error on startup — run
setup.batagain to re-download WinSCP. CONFIG ERROR: entity.json is missing or has blank: ...— the fields it lists couldn't be found in that entity'sentity.json(or the practice'spractice.json). Open the file and check those exact key names against the example above — a typo in the key name counts as missing.No .pdf files in <date>\but the folder isn't empty — the files in the date folder are probably TIFs. Add"insurance_file_type": "tif",at the top level of that entity'sentity.json(right underworkflow).- Every field shows missing at once — the section name itself is probably
wrong (must be exactly
ftps/sftp), or the file's structure got damaged while editing. Compare the overall shape againstEntities\EXAMPLE\entity.json. - The startup banner shows the wrong file type — the banner line
(
Entity: ... | File type: .pdf | ...) shows what was actually read fromentity.json, so it's the quickest way to confirm your edit took effect.