Add latest migration files and validation outputs
This commit is contained in:
parent
c63d49e208
commit
39982008d3
|
|
@ -0,0 +1,50 @@
|
|||
# Adobe Sign → DocuSign Migrator — Environment Variables
|
||||
# Copy this file to .env and fill in your values.
|
||||
# Never commit .env to version control.
|
||||
|
||||
# ─── Adobe Sign ──────────────────────────────────────────────────────────────
|
||||
|
||||
# OAuth app credentials from the Adobe Sign developer console
|
||||
ADOBE_CLIENT_ID=ats-58a336e4-3dd5-466d-bc5d-ba341a012694
|
||||
ADOBE_CLIENT_SECRET=4c9SRsLNEBn953hzR1wa7wL5VzHnD5k_
|
||||
# Auto-written by src/adobe_auth.py after the one-time OAuth flow.
|
||||
# Leave blank; they will be populated on first run.
|
||||
ADOBE_ACCESS_TOKEN="3AAABLblqZhDON9k_91_RhgUlZbpHx6luaPSmu7_Jj1hrPdmqCQ6ciQDVJVVvLMr__4v161k3kZc6c2fYbxsl5tA1IbmQni9T"
|
||||
ADOBE_REFRESH_TOKEN="3AAABLblqZhB6qLQOQ2H5oax-Ed3E6Nc0IqFupdB9UlKzAoWQ3Cb2u3lla4d6Vuquf9xHhGMfn68*"
|
||||
ADOBE_SIGN_BASE_URL=https://api.eu2.adobesign.com/api/rest/v6
|
||||
|
||||
# ─── DocuSign ────────────────────────────────────────────────────────────────
|
||||
|
||||
# Integration key (client ID) from the DocuSign developer console
|
||||
DOCUSIGN_CLIENT_ID=your-integration-key
|
||||
|
||||
# Client secret — only needed for the one-time Auth Code Grant consent flow
|
||||
DOCUSIGN_CLIENT_SECRET=your-client-secret
|
||||
|
||||
# GUID of the DocuSign user to impersonate via JWT grant
|
||||
# Found in the DocuSign admin UI under Users → user details
|
||||
DOCUSIGN_USER_ID=your-docusign-user-guid
|
||||
|
||||
# Account ID of the target DocuSign account
|
||||
# Found in the DocuSign admin UI under Settings → Account Profile
|
||||
DOCUSIGN_ACCOUNT_ID=your-docusign-account-id
|
||||
|
||||
# Path to the RSA private key file used for JWT signing
|
||||
# Generate a keypair in the DocuSign developer console and save the private key here
|
||||
DOCUSIGN_PRIVATE_KEY_PATH=/path/to/private.key
|
||||
|
||||
# OAuth auth server — use account-d.docusign.com for sandbox, account.docusign.com for production
|
||||
DOCUSIGN_AUTH_SERVER=account-d.docusign.com
|
||||
|
||||
# eSignature REST API base URL
|
||||
# Sandbox: https://demo.docusign.net/restapi
|
||||
# Production: https://na3.docusign.net/restapi (replace na3 with your shard)
|
||||
DOCUSIGN_BASE_URL=https://demo.docusign.net/restapi
|
||||
|
||||
# Redirect URI registered in your DocuSign app (used only during one-time consent flow)
|
||||
DOCUSIGN_REDIRECT_URI=http://localhost:8080/callback
|
||||
|
||||
# Auto-written by src/docusign_auth.py to cache the JWT access token.
|
||||
# Leave blank; they will be populated automatically.
|
||||
DOCUSIGN_ACCESS_TOKEN=
|
||||
DOCUSIGN_TOKEN_EXPIRY=
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,8 @@
|
|||
# Collaboration/Diagram Log
|
||||
|
||||
## Session: 2026-04-14
|
||||
- Architecture mermaid diagram block added to docs/architecture.md (data flow, main modules)
|
||||
- All new regressions and results summarized in validation/
|
||||
- This log is ready for markdown, diagrams, and collaborative session notes as agent/project evolves.
|
||||
|
||||
*Agent generated*
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# DocuSign Ingest Stub
|
||||
|
||||
"""
|
||||
Stub for DocuSign API ingest.
|
||||
- Loads mapped onboarding template data.
|
||||
- Would POST to DocuSign API if credentials configured
|
||||
"""
|
||||
import json
|
||||
from pathlib import Path
|
||||
from pprint import pprint
|
||||
|
||||
def push_to_docusign(template):
|
||||
print("(Stub) Would push the following template to DocuSign:")
|
||||
pprint(template)
|
||||
# Here you'd use requests to POST to DocuSign API endpoint
|
||||
# For MVP: stop here and log intended payload
|
||||
|
||||
if __name__ == "__main__":
|
||||
mapped = json.loads(Path("../validation/onboarding-mapping-eval.md").read_text(errors="ignore").split('---')[-1]) if False else None
|
||||
# For showcase: rerun mapping function from test_mapping.py
|
||||
import sys
|
||||
sys.path.append("../src")
|
||||
from test_mapping import map_adobe_fields_to_docusign_tabs
|
||||
fields = json.loads(Path("../sample-templates/onboarding-template-formfields.json").read_text())
|
||||
mapped = map_adobe_fields_to_docusign_tabs(fields)
|
||||
push_to_docusign(mapped)
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
"""
|
||||
migrate_paul_template.py
|
||||
------------------------
|
||||
End-to-end validation: downloads the most recently edited "Paul Adobe Template"
|
||||
from Adobe Sign, converts it to a DocuSign template JSON, and uploads it.
|
||||
|
||||
Usage:
|
||||
python3 src/migrate_paul_template.py
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
sys.path.insert(0, os.path.dirname(__file__))
|
||||
|
||||
from adobe_api import adobe_api_get, adobe_api_get_bytes
|
||||
|
||||
DOWNLOADS_DIR = Path(__file__).parent.parent / "downloads"
|
||||
MIGRATION_OUTPUT_DIR = Path(__file__).parent.parent / "migration-output"
|
||||
TEMPLATE_NAME = "Paul Adobe Template"
|
||||
|
||||
CLI_PATH = Path(__file__).parent.parent.parent / "docusign-direct" / "packages" / "esign-direct" / "build" / "cli.js"
|
||||
|
||||
|
||||
def safe_dirname(name):
|
||||
return "".join(c if c.isalnum() or c in " -_" else "_" for c in name).strip()
|
||||
|
||||
|
||||
def save_json(path, data):
|
||||
with open(path, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
||||
|
||||
def find_latest_paul_template():
|
||||
"""Return the metadata dict for the most recently modified 'Paul Adobe Template'."""
|
||||
print("Fetching template list from Adobe Sign...")
|
||||
result = adobe_api_get("libraryDocuments")
|
||||
all_templates = result.get("libraryDocumentList", [])
|
||||
print(f" Found {len(all_templates)} total template(s).")
|
||||
|
||||
matches = [t for t in all_templates if t.get("name", "") == TEMPLATE_NAME]
|
||||
if not matches:
|
||||
print(f"ERROR: No template named '{TEMPLATE_NAME}' found.")
|
||||
sys.exit(1)
|
||||
|
||||
print(f" Found {len(matches)} template(s) named '{TEMPLATE_NAME}':")
|
||||
for t in matches:
|
||||
print(f" ID: {t['id']} modifiedDate: {t.get('modifiedDate', 'n/a')}")
|
||||
|
||||
# Pick most recently modified
|
||||
latest = max(matches, key=lambda t: t.get("modifiedDate", ""))
|
||||
print(f"\n Using most recently modified: ID={latest['id']} modifiedDate={latest.get('modifiedDate', 'n/a')}")
|
||||
return latest
|
||||
|
||||
|
||||
def download_template(template):
|
||||
template_id = template["id"]
|
||||
template_name = template["name"]
|
||||
dir_name = f"{safe_dirname(template_name)}__{template_id[:8]}"
|
||||
out_dir = DOWNLOADS_DIR / dir_name
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
print(f"\nDownloading template to downloads/{dir_name}/")
|
||||
|
||||
# Full metadata
|
||||
metadata = adobe_api_get(f"libraryDocuments/{template_id}")
|
||||
save_json(out_dir / "metadata.json", metadata)
|
||||
|
||||
# Form fields
|
||||
try:
|
||||
form_fields = adobe_api_get(f"libraryDocuments/{template_id}/formFields")
|
||||
save_json(out_dir / "form_fields.json", form_fields)
|
||||
field_count = len(form_fields.get("fields", []))
|
||||
print(f" {field_count} form fields saved.")
|
||||
for f in form_fields.get("fields", []):
|
||||
val = f.get("validation", "")
|
||||
val_str = f"/ {val}" if val and val != "NONE" else ""
|
||||
print(f" {f['inputType']:15} {f.get('contentType',''):20} {val_str:10} '{f['name']}'")
|
||||
except Exception as e:
|
||||
print(f" WARNING: Could not fetch form fields: {e}")
|
||||
save_json(out_dir / "form_fields.json", {"error": str(e)})
|
||||
|
||||
# Document list + PDFs
|
||||
docs = adobe_api_get(f"libraryDocuments/{template_id}/documents")
|
||||
save_json(out_dir / "documents.json", docs)
|
||||
|
||||
for doc in docs.get("documents", []):
|
||||
doc_id = doc["id"]
|
||||
doc_name = doc.get("name", doc_id)
|
||||
if not doc_name.lower().endswith(".pdf"):
|
||||
doc_name += ".pdf"
|
||||
safe_name = safe_dirname(doc_name)
|
||||
pdf_path = out_dir / safe_name
|
||||
try:
|
||||
pdf_bytes = adobe_api_get_bytes(f"libraryDocuments/{template_id}/documents/{doc_id}")
|
||||
with open(pdf_path, "wb") as f:
|
||||
f.write(pdf_bytes)
|
||||
print(f" PDF saved ({len(pdf_bytes) // 1024}KB) → {safe_name}")
|
||||
except Exception as e:
|
||||
print(f" WARNING: Could not download PDF: {e}")
|
||||
|
||||
return out_dir
|
||||
|
||||
|
||||
def run_migration(template_dir: Path) -> Path:
|
||||
"""Convert the downloaded template folder to a DocuSign template JSON."""
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
from compose_docusign_template import compose_template
|
||||
|
||||
output_path = MIGRATION_OUTPUT_DIR / template_dir.name / "docusign-template.json"
|
||||
print(f"\nRunning migration: {template_dir.name}")
|
||||
template_dict, warnings = compose_template(str(template_dir), str(output_path))
|
||||
|
||||
print(f" Written: {output_path}")
|
||||
if warnings:
|
||||
print(" Warnings:")
|
||||
for w in warnings:
|
||||
print(f" WARNING: {w}")
|
||||
|
||||
# Print tab summary
|
||||
signers = template_dict.get("recipients", {}).get("signers", [])
|
||||
for signer in signers:
|
||||
tabs = signer.get("tabs", {})
|
||||
print(f" Tabs for '{signer['roleName']}':")
|
||||
for tab_type, tab_list in sorted(tabs.items()):
|
||||
for tab in tab_list:
|
||||
label = tab.get("tabLabel") or tab.get("groupName", "?")
|
||||
print(f" {tab_type:25} '{label}'")
|
||||
|
||||
return output_path
|
||||
|
||||
|
||||
def upload_to_docusign(output_path: Path):
|
||||
if not CLI_PATH.exists():
|
||||
print(f"\nWARNING: DocuSign CLI not found at {CLI_PATH}")
|
||||
print(f" Skipping upload. To upload manually:")
|
||||
print(f" node {CLI_PATH} templates create --file {output_path}")
|
||||
return
|
||||
|
||||
print(f"\nUploading to DocuSign...")
|
||||
# Use nvm's node (system node may be too old for the ?? operator in the CLI)
|
||||
nvm_node = Path.home() / ".nvm" / "alias" / "default"
|
||||
nvm_sh = Path.home() / ".nvm" / "nvm.sh"
|
||||
cmd = f'source {nvm_sh} && node {CLI_PATH} templates create --file "{output_path}"'
|
||||
result = subprocess.run(
|
||||
cmd, shell=True, executable="/bin/bash", capture_output=True, text=True
|
||||
)
|
||||
if result.returncode == 0:
|
||||
print(" Upload successful.")
|
||||
print(result.stdout)
|
||||
else:
|
||||
print(" Upload FAILED.")
|
||||
print(result.stdout)
|
||||
print(result.stderr)
|
||||
|
||||
|
||||
def main():
|
||||
DOWNLOADS_DIR.mkdir(exist_ok=True)
|
||||
MIGRATION_OUTPUT_DIR.mkdir(exist_ok=True)
|
||||
|
||||
template = find_latest_paul_template()
|
||||
template_dir = download_template(template)
|
||||
output_path = run_migration(template_dir)
|
||||
upload_to_docusign(output_path)
|
||||
|
||||
print(f"\nDone. DocuSign template JSON: {output_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
{
|
||||
"name": "Employee Onboarding Form",
|
||||
"description": "Migrated from Adobe Sign",
|
||||
"documents": [
|
||||
{
|
||||
"documentBase64": "JVBERi0xLjMKJZOMi54gUmVwb3J0TGFiIEdlbmVyYXRlZCBQREYgZG9jdW1lbnQgKG9wZW5zb3VyY2UpCjEgMCBvYmoKPDwKL0YxIDIgMCBSIC9GMiAzIDAgUiAvRjMgNSAwIFIKPj4KZW5kb2JqCjIgMCBvYmoKPDwKL0Jhc2VGb250IC9IZWx2ZXRpY2EgL0VuY29kaW5nIC9XaW5BbnNpRW5jb2RpbmcgL05hbWUgL0YxIC9TdWJ0eXBlIC9UeXBlMSAvVHlwZSAvRm9udAo+PgplbmRvYmoKMyAwIG9iago8PAovQmFzZUZvbnQgL0hlbHZldGljYS1Cb2xkIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nIC9OYW1lIC9GMiAvU3VidHlwZSAvVHlwZTEgL1R5cGUgL0ZvbnQKPj4KZW5kb2JqCjQgMCBvYmoKPDwKL0NvbnRlbnRzIDEwIDAgUiAvTWVkaWFCb3ggWyAwIDAgNjEyIDc5MiBdIC9QYXJlbnQgOSAwIFIgL1Jlc291cmNlcyA8PAovRm9udCAxIDAgUiAvUHJvY1NldCBbIC9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUkgXQo+PiAvUm90YXRlIDAgL1RyYW5zIDw8Cgo+PiAKICAvVHlwZSAvUGFnZQo+PgplbmRvYmoKNSAwIG9iago8PAovQmFzZUZvbnQgL0hlbHZldGljYS1PYmxpcXVlIC9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nIC9OYW1lIC9GMyAvU3VidHlwZSAvVHlwZTEgL1R5cGUgL0ZvbnQKPj4KZW5kb2JqCjYgMCBvYmoKPDwKL0NvbnRlbnRzIDExIDAgUiAvTWVkaWFCb3ggWyAwIDAgNjEyIDc5MiBdIC9QYXJlbnQgOSAwIFIgL1Jlc291cmNlcyA8PAovRm9udCAxIDAgUiAvUHJvY1NldCBbIC9QREYgL1RleHQgL0ltYWdlQiAvSW1hZ2VDIC9JbWFnZUkgXQo+PiAvUm90YXRlIDAgL1RyYW5zIDw8Cgo+PiAKICAvVHlwZSAvUGFnZQo+PgplbmRvYmoKNyAwIG9iago8PAovUGFnZU1vZGUgL1VzZU5vbmUgL1BhZ2VzIDkgMCBSIC9UeXBlIC9DYXRhbG9nCj4+CmVuZG9iago4IDAgb2JqCjw8Ci9BdXRob3IgKGFub255bW91cykgL0NyZWF0aW9uRGF0ZSAoRDoyMDI2MDQxNDIzNTM0OC0wNCcwMCcpIC9DcmVhdG9yIChhbm9ueW1vdXMpIC9LZXl3b3JkcyAoKSAvTW9kRGF0ZSAoRDoyMDI2MDQxNDIzNTM0OC0wNCcwMCcpIC9Qcm9kdWNlciAoUmVwb3J0TGFiIFBERiBMaWJyYXJ5IC0gXChvcGVuc291cmNlXCkpIAogIC9TdWJqZWN0ICh1bnNwZWNpZmllZCkgL1RpdGxlICh1bnRpdGxlZCkgL1RyYXBwZWQgL0ZhbHNlCj4+CmVuZG9iago5IDAgb2JqCjw8Ci9Db3VudCAyIC9LaWRzIFsgNCAwIFIgNiAwIFIgXSAvVHlwZSAvUGFnZXMKPj4KZW5kb2JqCjEwIDAgb2JqCjw8Ci9GaWx0ZXIgWyAvQVNDSUk4NURlY29kZSAvRmxhdGVEZWNvZGUgXSAvTGVuZ3RoIDc5NAo+PgpzdHJlYW0KR2F0biRfLEIjQSY7S1kmTUVRKWNML0I0IVtVa0lCVGxkL3IlL0E3YkhPdSNIZ3RGTWBTLSpdZVEwXklTTzpJc1kiQktdUV1Ebz9VOElSInJSSyNMVCFRRzslL2Y2OFBgPWVPXCFmRztYL0wjLHJebmU7WDdhZy1nKF9AMCYhUDxBZj08RVBwNjFRUlovQjBxNF1WIWFjPFYqLkg+YXI+cGZnVFVVRTcqPjchdSp0bjMjT0tFLWhXbycyU09dWm0pUzlXanA+UWxxIlYwZlgwbVwtSzZfUj41dWVZJXJIaElIXW1zW25YMlEiRm9Xa18/KmgvLVhQP2taJTpsY2t1NV5pLFNPYltMUzhrZiQ7QDVBQ21sbzhZM1hyRixjcGdjJ11Ya0wnODYmJFB1Yyxbbk1eRlktWSZqY0p0SyVpRiMlISZQJiciUU8oNlQ9XUc2N0YwXk89LyRIVTIjKWxWR0VqKFFsYXVhbVo0bkRWWHFpX0VJOU1FZTFhKV4tUzdvZmpnSjB0U0xBOlxJKFFzLjlkWlg9cSJcb19XIzEkVHMhM0pFVTFWWl1GSWRFP1BZaXJKOkxTIT1WOXMwXWtrWTArPmkkR0Q7V05VJCVWakBRMz5tQkg5JjRpU1VbcExdJ0NsVmUvNDRYREA0bnNmZzNcJkwnNV5wI28+XU1KQV9GNVlEbGs2Ni0vdSgqaz1vNiNZXitoMlkkUGBvRDNnTHAsREtIVFZibSxvU0FgWFpQNGZRPy1OZy1DSidLOS4zRCFkI3BMWT0pOmBtYFtFTzEsTWNHPmUlYFBKSFZaT1FCSTU0UjN0Zi8mSkovVGxZbz8pYy84JUghIUVpNWt0aktdIiRXKEJfL1FfKm5WXiMmazArTVwnLCVpJCY7IjZMYSZxaTVsSkFZZmJtaUdtL1JaXnVsbFIlLHA6SjAxMHQlX1RNc2RMQD9zT1FOT2wvaVVbVUVJajk/VEstLUdwb15nPmcwPmAqXCVyTW82VmY9W2xNOFRWOlpvYE8lWD9nV1M9IihrLmM4MHVQZ2wpZ0MhUzJDdGdBfj5lbmRzdHJlYW0KZW5kb2JqCjExIDAgb2JqCjw8Ci9GaWx0ZXIgWyAvQVNDSUk4NURlY29kZSAvRmxhdGVEZWNvZGUgXSAvTGVuZ3RoIDY3Ngo+PgpzdHJlYW0KR2F0VXA6TityUCZCNCpjTUtfYWdiNFZvU15xQ0kzLkAkcEEsLzA8YDJZSSxnbTlPNkEsLy9KPEdQVThxJkh0VD9iOFQoJnJGVTRiIkBFKG9HTCgmNFAyWUdSSjw3aGYmOS83K3FoRnVhaThUbkUvajldYHFmajRwOC1CNmZWMHRsI2pocmhfYGFPTnRiWCsxKW1kIyIsRyF1LCFUOFtOQjtEN1FKUk1wNXI3c0hTTz4nNjxoZzA4KjtPUE8oJGNxL0xjQi5dV3JgLS89Zk8hSTJnR0ZkJUtoL3EuVUllLVFgZTdfayxEZ042aUwiVmZEW04/Ii4nSyklNUZBRVZtY1I4b28jOCpRdU81UjRKcjUwKDtSZDtJYyJGYClPVkJtJ2JtPStkYScpN0E+Sm9oLm0oS09AWlNPYyg+N1Vja0VqUiwwKW5YZXVhKmxsRVFsTFNzaEBeKUJfQEFTKHVrRDonRTBGcVo9VCZdXFFVXjFJZ1BRbyQocFJFWEA8ZXFjTUZpVEBYXHAzUls6K2tmWDJrPTZEPHFQZ2VVOHVfUldnaURPPk03P3U/WXVBYi5bRiV0bVUjNT42bHUzVzUvIXFWLTJkR05eJHRgWipFbDReOkA4Y3FrNG8raiduSGpJU0sjNmpTJUBeW2xDYi1hVi1gWUVYMCs4dGxjKmJhSmRSYkAmTy8oN14zaEVWMmlbKS44Zihmbk5IU0YnL2Itcl1fU25JRlRWaCs4LjMoZnBsRiMmJVhBKV5XLSsqY05aY2JnY2RhaSkkQ0wwIys4blFqXk5LJTNWMkcpMzI1Y2xXRypTOT5vWjhOSE5OLlJEXVtcUlFcRUxjPFwncFhyS0ItT2xwKjViUlssWTQ6K2h1IzdKVi1WYnFgOEReZXIrYCN+PmVuZHN0cmVhbQplbmRvYmoKeHJlZgowIDEyCjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDA2MSAwMDAwMCBuIAowMDAwMDAwMTEyIDAwMDAwIG4gCjAwMDAwMDAyMTkgMDAwMDAgbiAKMDAwMDAwMDMzMSAwMDAwMCBuIAowMDAwMDAwNTI1IDAwMDAwIG4gCjAwMDAwMDA2NDAgMDAwMDAgbiAKMDAwMDAwMDgzNCAwMDAwMCBuIAowMDAwMDAwOTAyIDAwMDAwIG4gCjAwMDAwMDExNjMgMDAwMDAgbiAKMDAwMDAwMTIyOCAwMDAwMCBuIAowMDAwMDAyMTEzIDAwMDAwIG4gCnRyYWlsZXIKPDwKL0lEIApbPDA0YTQ1NjEzNWZkMGRhOGQ1OWIzNTNiMTliMjFhZGVlPjwwNGE0NTYxMzVmZDBkYThkNTliMzUzYjE5YjIxYWRlZT5dCiUgUmVwb3J0TGFiIGdlbmVyYXRlZCBQREYgZG9jdW1lbnQgLS0gZGlnZXN0IChvcGVuc291cmNlKQoKL0luZm8gOCAwIFIKL1Jvb3QgNyAwIFIKL1NpemUgMTIKPj4Kc3RhcnR4cmVmCjI4ODAKJSVFT0YK",
|
||||
"name": "OnboardingForm.pdf",
|
||||
"fileExtension": "pdf",
|
||||
"documentId": "1"
|
||||
}
|
||||
],
|
||||
"recipients": {
|
||||
"signers": [
|
||||
{
|
||||
"roleName": "SIGNER",
|
||||
"recipientId": "1",
|
||||
"routingOrder": "1",
|
||||
"tabs": {
|
||||
"textTabs": [
|
||||
{
|
||||
"tabLabel": "EmployeeName",
|
||||
"required": "true",
|
||||
"locked": "false",
|
||||
"documentId": "1",
|
||||
"pageNumber": "1",
|
||||
"xPosition": "100",
|
||||
"yPosition": "577"
|
||||
}
|
||||
],
|
||||
"dateSignedTabs": [
|
||||
{
|
||||
"tabLabel": "StartDate",
|
||||
"documentId": "1",
|
||||
"pageNumber": "1",
|
||||
"xPosition": "100",
|
||||
"yPosition": "537"
|
||||
}
|
||||
],
|
||||
"listTabs": [
|
||||
{
|
||||
"tabLabel": "Position",
|
||||
"required": "true",
|
||||
"documentId": "1",
|
||||
"pageNumber": "1",
|
||||
"xPosition": "100",
|
||||
"yPosition": "497",
|
||||
"listItems": [
|
||||
{
|
||||
"text": "Manager",
|
||||
"value": "Manager"
|
||||
},
|
||||
{
|
||||
"text": "Engineer",
|
||||
"value": "Engineer"
|
||||
},
|
||||
{
|
||||
"text": "Tech",
|
||||
"value": "Tech"
|
||||
},
|
||||
{
|
||||
"text": "HR",
|
||||
"value": "HR"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"checkboxTabs": [
|
||||
{
|
||||
"tabLabel": "Benefits",
|
||||
"required": "false",
|
||||
"documentId": "1",
|
||||
"pageNumber": "1",
|
||||
"xPosition": "100",
|
||||
"yPosition": "460"
|
||||
}
|
||||
],
|
||||
"radioGroupTabs": [
|
||||
{
|
||||
"groupName": "CommuteGroup",
|
||||
"documentId": "1",
|
||||
"radios": [
|
||||
{
|
||||
"pageNumber": "1",
|
||||
"xPosition": "100",
|
||||
"yPosition": "420",
|
||||
"value": "Car"
|
||||
},
|
||||
{
|
||||
"pageNumber": "1",
|
||||
"xPosition": "140",
|
||||
"yPosition": "420",
|
||||
"value": "Transit"
|
||||
},
|
||||
{
|
||||
"pageNumber": "1",
|
||||
"xPosition": "180",
|
||||
"yPosition": "420",
|
||||
"value": "Bike"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"signHereTabs": [
|
||||
{
|
||||
"tabLabel": "EmployeeSignature",
|
||||
"documentId": "1",
|
||||
"pageNumber": "2",
|
||||
"xPosition": "100",
|
||||
"yPosition": "460"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"roleName": "APPROVER",
|
||||
"recipientId": "2",
|
||||
"routingOrder": "2",
|
||||
"tabs": {
|
||||
"textTabs": [
|
||||
{
|
||||
"tabLabel": "HRNotes",
|
||||
"required": "false",
|
||||
"locked": "true",
|
||||
"documentId": "1",
|
||||
"pageNumber": "2",
|
||||
"xPosition": "100",
|
||||
"yPosition": "532"
|
||||
}
|
||||
],
|
||||
"signHereTabs": [
|
||||
{
|
||||
"tabLabel": "HRSignature",
|
||||
"documentId": "1",
|
||||
"pageNumber": "2",
|
||||
"xPosition": "300",
|
||||
"yPosition": "460"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
{
|
||||
"name": "Employee Onboarding Form",
|
||||
"description": "Migrated from Adobe Sign",
|
||||
"documents": [
|
||||
{
|
||||
"documentBase64": "...",
|
||||
"name": "OnboardingForm.pdf",
|
||||
"fileExtension": "pdf",
|
||||
"documentId": "1"
|
||||
}
|
||||
],
|
||||
"recipients": {
|
||||
"signers": [
|
||||
{
|
||||
"roleName": "SIGNER",
|
||||
"recipientId": "1",
|
||||
"email": "employee@example.com",
|
||||
"name": "Employee",
|
||||
"tabs": [
|
||||
{
|
||||
"tabLabel": "EmployeeName",
|
||||
"tabType": "text",
|
||||
"required": true,
|
||||
"recipientIndex": 0,
|
||||
"items": null,
|
||||
"readOnly": false
|
||||
},
|
||||
{
|
||||
"tabLabel": "StartDate",
|
||||
"tabType": "dateSigned",
|
||||
"required": true,
|
||||
"recipientIndex": 0,
|
||||
"items": null,
|
||||
"readOnly": false
|
||||
},
|
||||
{
|
||||
"tabLabel": "Position",
|
||||
"tabType": "list",
|
||||
"required": true,
|
||||
"recipientIndex": 0,
|
||||
"items": [
|
||||
"Manager",
|
||||
"Engineer",
|
||||
"Tech",
|
||||
"HR"
|
||||
],
|
||||
"readOnly": false
|
||||
},
|
||||
{
|
||||
"tabLabel": "Benefits",
|
||||
"tabType": "checkbox",
|
||||
"required": false,
|
||||
"recipientIndex": 0,
|
||||
"items": null,
|
||||
"readOnly": false
|
||||
},
|
||||
{
|
||||
"tabLabel": "CommuteOption",
|
||||
"tabType": "radio",
|
||||
"required": false,
|
||||
"recipientIndex": 0,
|
||||
"items": [
|
||||
"Car",
|
||||
"Transit",
|
||||
"Bike"
|
||||
],
|
||||
"readOnly": false
|
||||
},
|
||||
{
|
||||
"tabLabel": "EmployeeSignature",
|
||||
"tabType": "signHere",
|
||||
"required": true,
|
||||
"recipientIndex": 0,
|
||||
"items": null,
|
||||
"readOnly": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"roleName": "APPROVER",
|
||||
"recipientId": "2",
|
||||
"email": "hr@example.com",
|
||||
"name": "HR Representative",
|
||||
"tabs": [
|
||||
{
|
||||
"tabLabel": "HRNotes",
|
||||
"tabType": "text",
|
||||
"required": false,
|
||||
"recipientIndex": 1,
|
||||
"items": null,
|
||||
"readOnly": true
|
||||
},
|
||||
{
|
||||
"tabLabel": "HRSignature",
|
||||
"tabType": "signHere",
|
||||
"required": true,
|
||||
"recipientIndex": 1,
|
||||
"items": null,
|
||||
"readOnly": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": "created"
|
||||
}
|
||||
Loading…
Reference in New Issue