Overview
OptiFlow’s contact management system provides a centralized database for all your business relationships. Manage customers, suppliers, optometrists, and other contacts with detailed information, relationship tracking, and complete activity history.
Contacts are workspace-scoped, meaning each workspace maintains its own separate contact database while sharing the same users across the platform.
Key Features
Multi-Type Contacts Manage customers, suppliers, and optometrists with type-specific fields and workflows.
Relationship Tracking Link related contacts (family members, business partners) to share information and activity.
Activity History View complete transaction history including invoices, quotations, prescriptions, and payments.
Bulk Import Import contacts from CSV files with duplicate detection and validation.
Customers
Suppliers
Optometrists
Contacts who purchase products or services:
Credit limit tracking
Payment history
Outstanding balances
Invoice generation
// Create customer
$customer = Contact :: create ([
'contact_type' => ContactType :: Customer ,
'name' => 'John Smith' ,
'email' => '[email protected] ' ,
'credit_limit' => 5000.00 ,
]);
// Check if customer
if ( $contact -> isCustomer ()) {
// Customer-specific logic
}
Contacts who supply products:
Product stock tracking
Purchase order history
Payment terms
// Create supplier
$supplier = Contact :: create ([
'contact_type' => ContactType :: Supplier ,
'name' => 'ACME Supplies Inc' ,
'email' => '[email protected] ' ,
]);
// Get products supplied
$suppliedStocks = $supplier -> suppliedStocks ;
// Check if supplier
if ( $contact -> isSupplier ()) {
// Supplier-specific logic
}
Eye care professionals (specialized for optical businesses):
Prescription tracking
Professional credentials
Referral tracking
// Create optometrist
$optometrist = Contact :: create ([
'contact_type' => ContactType :: Optometrist ,
'name' => 'Dr. Sarah Johnson' ,
'email' => '[email protected] ' ,
]);
Core Fields
// Contact model (app/Models/Contact.php)
$contact = Contact :: create ([
'workspace_id' => $workspace -> id ,
'contact_type' => ContactType :: Customer ,
'name' => 'John Smith' ,
'email' => '[email protected] ' ,
// Phone numbers
'phone_primary' => '+1-555-0100' ,
'phone_secondary' => '+1-555-0101' ,
'mobile' => '+1-555-0102' ,
'fax' => '+1-555-0199' ,
// Identification
'identification_type' => 'passport' ,
'identification_number' => 'AB123456' ,
// Business info
'credit_limit' => 10000.00 ,
'status' => 'active' ,
'observations' => 'Preferred customer' ,
// Custom data
'metadata' => [
'customer_since' => '2020-01-01' ,
'preferred_payment' => 'wire_transfer' ,
],
]);
Name : Full name or business name
Email : Primary email address
Phone Numbers : Primary, secondary, mobile, and fax
Identification : Type and number (passport, ID card, tax ID)
Credit Limit : Maximum credit allowed
Status : Active or inactive
Observations : Internal notes
Metadata : Custom JSON data
Address Management
Contacts support multiple addresses:
// Add address to contact
$address = $contact -> addresses () -> create ([
'address_line_1' => '123 Main Street' ,
'address_line_2' => 'Suite 100' ,
'city' => 'New York' ,
'state' => 'NY' ,
'postal_code' => '10001' ,
'country' => 'USA' ,
'is_primary' => true ,
]);
// Get primary address
$primaryAddress = $contact -> primaryAddress ;
// Get all addresses
$addresses = $contact -> addresses ;
// Get formatted full address
$fullAddress = $contact -> full_address ;
Link related contacts together:
// Create relationship between contacts
$contact -> relationships () -> attach ( $relatedContact -> id , [
'description' => 'Spouse' ,
]);
// Get all related contacts
$relatedContacts = $contact -> relationships ;
// Get contact IDs including self and related
$allContactIds = $contact -> relatedContactIdsWithSelf ();
// [1, 4, 7] - Includes this contact + related contacts
Use Cases for Relationships
Family Members : Link family members to share invoices and prescriptions
Business Partners : Connect related business entities
Parent-Child Companies : Link corporate structures
Referral Networks : Track referral sources
When viewing activity for a contact, OptiFlow includes transactions from all related contacts, providing a complete family or business unit view.
Activity Tracking
Transaction History
// Get contact activity (app/Http/Controllers/ContactController.php:95)
$contactIds = $contact -> relatedContactIdsWithSelf ();
// Get invoices (including related contacts)
$invoices = Invoice :: whereIn ( 'contact_id' , $contactIds )
-> with ([ 'documentSubtype' , 'contact' ])
-> orderByDesc ( 'issue_date' )
-> limit ( 10 )
-> get ();
// Get quotations
$quotations = Quotation :: whereIn ( 'contact_id' , $contactIds )
-> with ([ 'documentSubtype' , 'contact' ])
-> orderByDesc ( 'issue_date' )
-> limit ( 10 )
-> get ();
// Get prescriptions (optical businesses)
$prescriptions = $contact -> prescriptions ()
-> with ([ 'optometrist' ])
-> orderByDesc ( 'created_at' )
-> limit ( 10 )
-> get ();
Financial Summary
// Calculate contact statistics
$stats = [
'total_invoices' => Invoice :: whereIn ( 'contact_id' , $contactIds ) -> count (),
'total_invoiced' => Invoice :: whereIn ( 'contact_id' , $contactIds ) -> sum ( 'total_amount' ),
'total_paid' => Invoice :: whereIn ( 'contact_id' , $contactIds )
-> whereIn ( 'status' , [ 'paid' , 'partially_paid' ])
-> get ()
-> sum ( fn ( $inv ) => $inv -> total_amount - $inv -> amount_due ),
'pending_amount' => Invoice :: whereIn ( 'contact_id' , $contactIds )
-> whereNotIn ( 'status' , [ 'paid' , 'cancelled' ])
-> sum ( 'total_amount' ),
];
Add internal comments to contacts:
// Contacts support comments (app/Models/Contact.php:91)
$comment = $contact -> comments () -> create ([
'body' => 'Customer prefers morning delivery' ,
'commentator_id' => auth () -> id (),
]);
// Get all comments
$comments = $contact -> comments ;
// Comments support nested replies
$reply = $comment -> comments () -> create ([
'body' => 'Noted for next order' ,
'commentator_id' => auth () -> id (),
]);
Use the ContactSearch helper for efficient lookups:
use App\Support\ ContactSearch ;
$search = app ( ContactSearch :: class );
// Search active contacts
$results = $search -> searchActive ( 'john smith' );
// Search customers only
$customers = $search -> searchCustomers ( 'acme' );
// Find customer by ID
$customer = $search -> findCustomerById ( $customerId );
// Convert to select option format
$option = $search -> toOption ( $contact );
Bulk Import
Import contacts from CSV files:
// Using ContactImportController
use App\Http\Controllers\ ProcessContactImportController ;
// Upload CSV file
$import = ContactImport :: create ([
'workspace_id' => $workspace -> id ,
'file_path' => $filePath ,
'user_id' => auth () -> id (),
]);
// Process import
ProcessContactImportAction :: handle ( $import );
// Import includes:
// - Duplicate detection
// - Data validation
// - Error reporting
// - Progress tracking
Duplicate Detection
// Check for duplicate contacts
use App\Http\Controllers\ CheckContactDuplicatesController ;
// Detects duplicates based on:
// - Name similarity
// - Email match
// - Phone number match
// - Identification number
By Type
// Get customers only
$customers = Contact :: customers () -> get ();
// Get suppliers only
$suppliers = Contact :: suppliers () -> get ();
// Get optometrists
$optometrists = Contact :: optometrists () -> get ();
// By specific type
$contacts = Contact :: ofType ( ContactType :: Customer -> value ) -> get ();
By Status
// Active contacts only
$active = Contact :: where ( 'status' , 'active' ) -> get ();
// Check if active
if ( $contact -> isActive ()) {
// Contact is active
}
By Workspace
// Contacts in current workspace (automatic)
$contacts = Contact :: all ();
// Contacts in specific workspace
$contacts = Contact :: forWorkspace ( $workspace ) -> get ();
// All contacts (admin only)
$allContacts = Contact :: withoutWorkspaceScope () -> get ();
Use Cases
Track customer information, purchase history, outstanding balances, and credit limits for retail or B2B sales.
Maintain supplier contact information, track which products they supply, and manage purchasing relationships.
Link family members together to share invoices, prescriptions, and payment history for optical or healthcare businesses.
Manage relationships with optometrists, referral sources, and other professional contacts.
Best Practices
Complete Information Fill in as much contact information as possible for better customer service and communication.
Regular Updates Keep contact information current by updating addresses, phone numbers, and email addresses when customers notify you of changes.
Use Relationships Link related contacts to provide better service and see complete family or business unit activity.
Credit Limits Set appropriate credit limits for customers to manage risk and automate credit approval.
API Reference
Key contact model methods:
isCustomer() - Check if contact is a customer
isSupplier() - Check if contact is a supplier
isActive() - Check if contact is active
relatedContactIdsWithSelf() - Get IDs including relationships
addresses() - Relationship to Address records
primaryAddress() - Get primary address
relationships() - Relationship to related contacts
invoices() - Relationship to Invoice records
quotations() - Relationship to Quotation records
suppliedStocks() - Relationship to supplied ProductStock
prescriptions() - Relationship to Prescription records
comments() - Relationship to Comment records
Model location: app/Models/Contact.php:1
Controller location: app/Http/Controllers/ContactController.php:1