Skip to main content
Contacts are central to OptiFlow, representing customers, suppliers, and other business relationships. Proper contact management ensures smooth invoicing, quotations, and reporting.

Overview

Contact management features:
  • Unified customer and supplier database
  • Multiple contact types (customer, supplier, both)
  • Contact relationships (family members, business partners)
  • Comprehensive contact information (addresses, IDs, phones, emails)
  • Activity history (invoices, quotations, payments)
  • Bulk import from Excel/CSV
  • Duplicate detection

Contact Types

OptiFlow supports different contact classifications:
TypeCodeUsage
CustomercustomerEntities you sell to
SuppliersupplierEntities you buy from
BothbothEntities you both buy from and sell to
Reference: ContactType enum in app/Enums/ContactType.php

Creating a Contact

1

Navigate to Contacts

Go to ContactsCreate ContactReference: ContactController::create() in app/Http/Controllers/ContactController.php:42Requires contacts:create permission.
2

Enter Basic Information

Required Fields:
  • Name: Contact’s full name or business name
  • Contact Type: Customer, Supplier, or Both
Optional Fields:
  • Commercial Name: Trading name (if different from legal name)
  • Email: Primary email address
  • Phone: Primary phone number
  • Mobile: Mobile phone number
  • Website: Company website
// Available contact types loaded in the form
'contact_types' => collect(ContactType::cases())
    ->map(fn ($type) => [
        'value' => $type->value,
        'label' => $type->label(),
    ]);
3

Add Identification

Configure identification documents:Identification Type: Select from:
  • RNC (Registro Nacional de Contribuyentes) - Tax ID
  • Cédula - National ID card
  • Pasaporte - Passport
  • Other identification types
Identification Number: Enter the ID number
For Dominican Republic businesses, RNC is mandatory for proper tax compliance and invoice generation.
Reference: IdentificationType enum defines available ID types
'identification_types' => collect(IdentificationType::cases())
    ->map(fn ($type) => [
        'value' => $type->value,
        'label' => $type->label(),
    ]);
4

Add Address Information

Primary Address (Optional but recommended):
  • Street address
  • City
  • State/Province
  • Postal code
  • Country
The primary address is used for:
  • Invoice billing address
  • Delivery address (default)
  • Correspondence
You can add multiple addresses per contact. The first address created becomes the primary address.
5

Configure Relationships

Link this contact to related contacts:Use Cases:
  • Family members (parent, child, spouse)
  • Business partners
  • Subsidiaries
  • Alternative contacts
To Add Relationship:
  1. Search for existing contact
  2. Select relationship type or add description
  3. Add to relationships list
Benefits:
  • View consolidated activity across related contacts
  • Track family/group purchasing patterns
  • Share notes and history
Reference: Contact relationships are many-to-many with descriptions
// From ContactController::show()
$contactIds = $contact->relatedContactIdsWithSelf();

// Invoices query includes related contacts
$invoices = Invoice::query()
    ->whereIn('contact_id', $contactIds)
    ->get();
6

Save Contact

Click Create ContactThe system:
  1. Validates required fields
  2. Checks for potential duplicates (optional)
  3. Creates contact record
  4. Creates primary address (if provided)
  5. Establishes relationships
  6. Redirects to contact detail page
Reference: CreateContactAction::handle() in app/Actions/CreateContactAction.php

Contact Information Fields

Complete Field List

Identity:
  • Name (required)
  • Commercial name
  • Identification type
  • Identification number
Communication:
  • Email
  • Phone
  • Mobile
  • Website
Classification:
  • Contact type (Customer/Supplier/Both)
  • Tags or categories (if configured)
Address:
  • Multiple addresses supported
  • Primary address designation
  • Full address components
Relationships:
  • Related contacts with descriptions
  • Bidirectional relationships
Financial:
  • Credit limit (optional)
  • Payment terms preference
  • Tax classification

Viewing Contact Details

1

Navigate to Contact

Go to Contacts → Select a contact from the listReference: ContactController::show() in app/Http/Controllers/ContactController.php:82
2

Overview Tab

View contact summary:
  • Basic information
  • Primary address
  • Recent activity
  • Quick statistics
Statistics Shown:
$stats = [
    'total_invoices' => (clone $invoiceQuery)->count(),
    'total_quotations' => (clone $quotationQuery)->count(),
    'total_invoiced' => (clone $invoiceQuery)->sum('total_amount'),
    'total_paid' => /* sum of payments */,
    'pending_amount' => /* outstanding balance */,
];
3

Invoices Tab

View all invoices for this contact:
  • Invoice number and date
  • Total amount
  • Status (Paid, Pending, Overdue)
  • Payment status
  • Quick actions (view, download PDF)
Limited to 10 most recent, with link to see all.
4

Quotations Tab

View all quotations:
  • Quotation number and date
  • Status (Pending, Approved, Converted)
  • Total quoted amount
  • Actions (view, convert to invoice)
5

Activity Tab

Complete activity log:
  • Contact changes
  • Invoice created/paid
  • Quotations sent
  • Payments received
  • Notes added
  • User who performed action
  • Timestamp
6

Comments Tab

Internal notes and comments:
  • Add notes about the contact
  • Communication history
  • Special instructions
  • Threaded discussions
Reference: Contact implements Commentable interface using HasComments trait

Editing Contacts

1

Open Contact Editor

From contact detail page, click Edit ContactReference: ContactController::edit() in app/Http/Controllers/ContactController.php:170Requires contacts:edit permission.
2

Modify Information

Update any contact fields:
  • Basic information
  • Contact type
  • Identification
  • Addresses
  • Relationships
Changing a contact’s identification number may affect tax reporting and compliance. Ensure the change is legitimate and properly documented.
3

Save Changes

Click Update ContactChanges are tracked in the activity log with:
  • Fields changed
  • Old and new values
  • User who made the change
  • Timestamp
Reference: UpdateContactAction::handle()

Contact Relationships

Setting Up Relationships

Contact relationships allow linking related individuals or businesses: Relationship Types (custom descriptions):
  • “Parent” / “Child”
  • “Spouse”
  • “Business Partner”
  • “Subsidiary”
  • “Primary Contact” / “Alternative Contact”
  • “Referral Source”

Benefits of Relationships

  1. Consolidated Reporting: View all invoices and quotations for a family or group
  2. Shared History: See complete interaction history
  3. Cross-References: Easy navigation between related contacts

Adding Relationships

1

Edit Contact

Navigate to contact and click Edit
2

Search for Related Contact

Use the relationship search field:
  • Type contact name or ID
  • Select from results
  • Contact cannot be related to itself
// Search excludes the current contact
$contactSearch->searchActive(
    (string) $request->string('relationship_search'),
    $contact->id  // Exclude this contact from results
);
3

Add Description

Describe the relationship:
  • “Mother of [contact]”
  • “Alternative phone for [contact]”
  • “Partner”
4

Save

Relationship is bidirectional - appears on both contacts

Importing Contacts

Bulk import contacts from Excel or CSV files.
1

Navigate to Import

Go to ContactsImport ContactsReference: ContactImportController in app/Http/Controllers/ContactImportController.php
2

Upload File

Supported formats:
  • Excel (.xlsx, .xls)
  • CSV (.csv)
Requirements:
  • First row should contain headers
  • At minimum, include contact names
Reference: CreateContactImportAction parses file using ParseExcelFileAction or ParseCsvFileAction
3

Map Columns

Map your file columns to OptiFlow contact fields:Your File ColumnOptiFlow Field
  • “Customer Name” → Name
  • “Tax ID” → Identification Number
  • “Email Address” → Email
  • etc.
Available fields from ContactImport::getAvailableFields():
  • name
  • commercial_name
  • email
  • phone
  • mobile
  • identification_type
  • identification_number
  • contact_type
  • address
  • city
  • state
  • postal_code
  • country
// Preview data shown for verification
'previewData' => array_slice($contactImport->import_data ?? [], 0, 5)
4

Validate Data

Review validation results:
  • ✅ Valid rows (will be imported)
  • ⚠️ Warnings (will import with caution)
  • ❌ Errors (will be skipped)
Common issues:
  • Missing required fields (name)
  • Invalid email formats
  • Duplicate identification numbers
Reference: ValidateContactImportDataAction
5

Process Import

Click Import ContactsSystem processes:
  1. Validates each row
  2. Checks for duplicates
  3. Creates contact records
  4. Creates addresses
  5. Generates import summary
Reference: ProcessContactImportAction::handle()
6

Review Results

Import summary shows:
  • Total rows processed
  • Successfully imported
  • Skipped (with reasons)
  • Duplicates detected
  • Link to imported contacts

Duplicate Detection

When importing, the system checks for duplicates based on:
  • Identification number (if provided)
  • Email address
  • Exact name match
Duplicate handling options:
  • Skip duplicates
  • Update existing contacts
  • Create anyway (with warning)
Reference: CheckContactDuplicatesController provides duplicate checking Efficient contact search throughout OptiFlow:

Search Locations

  1. Contact List Page: Full-text search with filters
  2. Invoice/Quotation Creation: Customer search dropdown
  3. Quick Search: Global search bar

Search Criteria

Contacts can be found by:
  • Name (partial match)
  • Commercial name
  • Identification number
  • Email
  • Phone number
// ContactSearch::searchCustomers() implementation
public function searchCustomers(string $query): array
{
    return Contact::query()
        ->where(function ($q) use ($query) {
            $q->where('name', 'like', "%{$query}%")
              ->orWhere('identification_number', 'like', "%{$query}%")
              ->orWhere('email', 'like', "%{$query}%")
              ->orWhere('phone', 'like', "%{$query}%");
        })
        ->whereIn('type', ['customer', 'both'])
        ->limit(20)
        ->get()
        ->map(fn ($contact) => $this->toOption($contact))
        ->toArray();
}

Search Filters

On contact list page:
  • Contact type (Customer/Supplier/Both)
  • Active/Inactive status
  • Tags or categories
  • Date created

Deleting Contacts

1

Navigate to Contact

Open the contact you want to delete
2

Click Delete

Click Delete Contact buttonReference: ContactController::destroy() - requires contacts:delete permission
3

Confirm Deletion

System checks if contact can be deleted:Cannot delete if:
  • Contact has invoices
  • Contact has quotations
  • Contact has payments
  • Contact has other related records
Solution for contacts with records:
  • Mark as inactive instead of deleting
  • Or remove as a “soft delete” (if configured)
Reference: DeleteContactAction::handle()
Deleting contacts is permanent and cannot be undone. For contacts with transaction history, consider marking them as inactive instead.

Best Practices

Complete Contact Information: Fill in as much information as possible. Complete contact records improve reporting and customer service.
Use Relationships: Link family members and related businesses to track group purchasing and provide better service.
Regular Cleanup: Periodically review and merge duplicate contacts, update outdated information.
Categorize Contacts: Use consistent contact types and tags for better segmentation and reporting.
Document Interactions: Use comments to record important customer conversations, preferences, and special instructions.

Common Scenarios

Scenario: Family Group Management

Situation: Optometry clinic with family patients
1

Create Primary Contact

Create contact for head of household
2

Create Family Members

Create individual contacts for spouse and children
3

Link Relationships

Add relationships:
  • Spouse relationship
  • Parent-child relationships
4

View Consolidated

From any family member, view complete family history of invoices and quotations

Scenario: Corporate Account

Situation: Business with multiple departments or contacts
1

Create Company Contact

Main business entity with RNC
2

Create Department Contacts

Individual contacts for departments (if needed)
3

Link as Subsidiaries

Relationship: “Department of [Company]“

Troubleshooting

Cannot Create Contact - Duplicate Error

Problem: “A contact with this identification number already exists” Solution:
  1. Search for existing contact
  2. Update existing contact instead
  3. Or use different identification type if legitimately different entity
Problem: Contact exists but doesn’t show in invoice customer search Cause: Contact type is set to “Supplier” only Solution:
  1. Edit the contact
  2. Change type to “Customer” or “Both”
Problem: Invoice was created but doesn’t appear on contact detail page Investigation:
  1. Check if invoice was created for a related contact instead
  2. Verify invoice is in the current workspace

Build docs developers (and LLMs) love