QuickBooks 2-Way Invoice Synchronization
v0.1.0Certified 2-way sync for QuickBooks Online and Desktop, zero-PHI accounting payload, idempotency, and consent gating.
QuickBooks 2-Way Invoice Synchronization
The QuickBooks Synchronization bounded context connects clinical dental procedures directly to Intuit QuickBooks (quickbooks.intuit.com). It provides certified 2-way invoice and payment synchronization for both QuickBooks Online and QuickBooks Desktop while enforcing zero-PHI compliance and patient billing consent gates.
Integration Architecture & Scope
The QuickBooks integration is dedicated strictly to itemized dental patient billing and payment receipts. Practice inventory, scheduling, odontograms, and clinical EMR data remain strictly managed within Obelawium:
[Chairside Operatory Encounter Completed]
|
(LedgerService::charge())
v
[DentalInvoice Created]
|
Has Active Billing Consent?
(ConsentType::BILLING)
/ \
NO YES
| |
[Blocked by Consent] [Zero-PHI Payload Extracted]
(Audit Flag Raised) |
v
[Idempotent Sync Job]
|
+----------------+----------------+
| |
v v
[QuickBooks Online] [QuickBooks Desktop]
(REST OAuth 2.0 API) (Intuit Web Connector QWC)
Zero-PHI Compliance Invariant
Because accounting platforms are outside the clinic’s internal healthcare compliance boundary, Obelawium Dental enforces a strict Zero-PHI Transmission Rule:
| Permitted in QuickBooks Payload | Strictly Prohibited (Filtered Out) |
|---|---|
ADA/CDT Code (e.g. CDT: D2740) | Patient First or Last Name |
| Standard CDT Description | Patient Social Security Number (SSN) |
| Unit Price & Quantity | Date of Birth or Age |
| Invoice Total & Insurance Share | Clinical Chart Notes or Diagnostics |
Opaque Ledger Reference (e.g. INV-9041) | Medical History & Health Alerts |
| External QuickBooks Customer ID Token | Radiographs or Odontogram Findings |
Patient Billing Consent Gating Invariant
Before any invoice payload is compiled or transmitted to Intuit, QuickBooksSyncService validates that the patient has granted active consent for third-party accounting:
$hasConsent = ium()->dental()->patients()->hasActiveConsent($invoice->patient_id, ConsentType::BILLING)
|| ium()->dental()->patients()->hasActiveConsent($invoice->patient_id, ConsentType::THIRD_PARTY_PAYMENT);
if (! $hasConsent) {
// Record BLOCKED_BY_CONSENT status and throw exception
throw QuickBooksSyncException::consentMissing($invoiceId);
}
If consent was not granted or was subsequently revoked, the sync job enters BLOCKED_BY_CONSENT status, halting the transmission until formal authorization is provided.
QuickBooks Online vs Desktop Support
1. QuickBooks Online (QBO)
- Authenticates via secure Intuit REST OAuth 2.0 protocol.
- Directly creates itemized
SalesItemLineDetailrecords against the practice’s QuickBooks Realm. - Immediate real-time response.
2. QuickBooks Desktop (QBD)
- Compatible with QuickBooks Pro, Premier, and Enterprise editions.
- Communicates asynchronously via the standard Intuit Web Connector (QWC) XML pipeline.
- Synchronizes when the clinic accountant runs the scheduled Web Connector queue.
Idempotency & Duplicate Prevention
Every sync job requires an idempotency_key (e.g. hash('invoice-' . $invoiceId . '-' . $version)). If network timeouts or webhook retries trigger a duplicate call, the service returns the existing QuickBooksSyncJob without re-posting to QuickBooks:
use Obelaw\Ium\Dental\Enums\QuickBooksSyncStatus;
enum QuickBooksSyncStatus: string
{
case PENDING = 'pending';
case SYNCING = 'syncing';
case SYNCED = 'synced';
case BLOCKED_BY_CONSENT = 'blocked_by_consent';
case FAILED = 'failed';
}
Fluent Service Operations
All synchronization actions are invoked via ium()->dental()->quickBooks():
1. Syncing a Dental Invoice
use Obelaw\Ium\Dental\Data\SyncQuickBooksInvoiceDto;
$syncJob = ium()->dental()->quickBooks()->syncInvoice(SyncQuickBooksInvoiceDto::from([
'invoice_id' => $invoice->id,
'idempotency_key' => 'INV-SYNC-' . $invoice->id . '-' . time(),
'is_desktop_qwc' => false, // Set true for QuickBooks Desktop Web Connector
'actor_id' => 'USER-BILLING-01',
]));
echo $syncJob->sync_status->value; // 'synced'
echo $syncJob->qbo_transaction_id; // 'QB-TXN-QBO-6789ABCD'
2. Syncing Payment Receipts
When copays or insurance claims are posted to the patient ledger, synchronize the payment receipt to mark the invoice paid inside QuickBooks:
$paymentJob = ium()->dental()->quickBooks()->syncPayment(
paymentId: $payment->id,
actorId: 'USER-BILLING-01'
);
3. Reviewing Sync Audit History
$history = ium()->dental()->quickBooks()->getSyncHistory(
resourceType: 'invoice',
resourceId: $invoice->id
);
foreach ($history as $job) {
echo "Attempt {$job->attempts}: {$job->sync_status->value} at {$job->synced_at}\n";
}
Emitted Domain Events
| Event Class | Trigger | Payload |
|---|---|---|
QuickBooksInvoiceSynced | Dispatched when an invoice is successfully acknowledged by Intuit. | QuickBooksSyncJob $job |