v1.0.0

Customer Relationship { .text-brand }

Modular CRM logic for Laravel. Manage contacts, companies, leads, opportunities, and pipelines through a clean fluent API — pure business logic, no UI, no bloat.

Getting Started

Installation

$ composer require obelaw/ium-crm

Publish Configuration

$ php artisan vendor:publish --tag=ium-crm-config

Run Migrations

$ php artisan migrate

Requirements

  • PHP 8.2+
  • Laravel 10+
  • MySQL 8.0+ or PostgreSQL 14+

Contacts

Contacts are the core entity in IUM-CRM. They can represent individuals or companies, and can be tagged, filtered, and linked to companies via roles.

Create a Contact

ium()->crm()->contacts()->create([
    'type' => 'individual', // individual | company
    'first_name' => 'Ahmed',
    'last_name' => 'Al-Omari',
    'email' => '[email protected]',
    'phone' => '+966500000000',
    'tags' => ['vip', 'wholesale'],
]);

Find, Update & Delete

// Find by ID
ium()->crm()->contacts()->find('CON-001');

// List with filters
ium()->crm()->contacts()->list(tag: 'vip', type: 'individual');

// Update
ium()->crm()->contacts()->find('CON-001')->update([
    'phone' => '+966511111111',
]);

// Attach to company
ium()->crm()->contacts()->find('CON-001')
    ->attachToCompany($company, role: 'manager');

// Delete
ium()->crm()->contacts()->find('CON-001')->delete();

Companies

Companies represent organizations in your CRM. You can associate multiple contacts to a company and retrieve all linked opportunities.

Create a Company

ium()->crm()->companies()->create([
    'name' => 'Advanced Technology Co.',
    'domain' => 'tech-advanced.com',
    'industry' => 'technology',
    'size' => '50-200',
    'country' => 'SA',
    'tags' => ['enterprise'],
]);
// Get all contacts in a company
ium()->crm()->companies()->find('COMP-001')->contacts();

// Get all opportunities for a company
ium()->crm()->companies()->find('COMP-001')->opportunities();

// Update
ium()->crm()->companies()->find('COMP-001')->update([
    'size' => '200-500',
]);

Leads

Leads track potential customers at the top of your funnel. Score them, qualify using BANT criteria, and convert them directly into pipeline opportunities.

Create & Qualify

// Create
ium()->crm()->leads()->create([
    'contact_id' => $contact->id,
    'source' => 'website', // website | referral | cold-call | social
    'score' => 75,        // 0–100
    'notes' => 'Interested in Enterprise package',
]);

// Qualify (BANT)
ium()->crm()->leads()->find('LEAD-001')->qualify([
    'budget' => 50000,
    'authority' => true,
    'need' => true,
    'timeline' => 'Q3-2026',
]);

Convert & Disqualify

// Convert to Opportunity
ium()->crm()->leads()->find('LEAD-001')
    ->convert(pipeline: 'default');

// Disqualify
ium()->crm()->leads()->find('LEAD-001')
    ->disqualify(reason: 'no-budget');

// List with filters
ium()->crm()->leads()->list(status: 'new', source: 'website');
ium()->crm()->leads()->list(score: ['min' => 60]);
  • new — Just created
  • contacted — Reached out
  • qualified — Meets criteria
  • disqualified — Not a fit
  • website — Website form
  • referral — Word of mouth
  • cold-call — Outbound call
  • social — Social media

:::

Opportunities

Opportunities represent active deals in your pipeline. Move them through stages, track deal value and probability, and close them as won or lost.

Create an Opportunity

ium()->crm()->opportunities()->create([
    'contact_id' => $contact->id,
    'pipeline_id' => 'sales-pipeline',
    'stage' => 'discovery',
    'value' => 25000.00,
    'currency' => 'SAR',
    'probability' => 60,
    'expected_at' => '2026-09-01',
]);

Manage Stages & Close

// Move stage
ium()->crm()->opportunities()->find('OPP-001')
    ->moveTo(stage: 'proposal');

// Close won
ium()->crm()->opportunities()->find('OPP-001')
    ->close(outcome: 'won');

// Close lost with reason
ium()->crm()->opportunities()->find('OPP-001')
    ->close(outcome: 'lost', reason: 'chose-competitor');

// Attach PIM products
ium()->crm()->opportunities()->find('OPP-001')
    ->attachProducts([
        ['sku' => 'PKG-ENTERPRISE', 'qty' => 1, 'price' => 25000],
    ]);

// Link OMS order
ium()->crm()->opportunities()->find('OPP-001')
    ->linkOrder('ORD-2026-001');

Pipelines

Pipelines define the stages that opportunities progress through. Each stage carries an order and probability weight for accurate forecasting.

Create a Pipeline

ium()->crm()->pipelines()->create([
    'name' => 'Sales Pipeline',
    'stages' => [
        ['name' => 'Discovery', 'order' => 1, 'probability' => 20],
        ['name' => 'Proposal', 'order' => 2, 'probability' => 40],
        ['name' => 'Negotiation', 'order' => 3, 'probability' => 70],
        ['name' => 'Closed Won', 'order' => 4, 'probability' => 100],
        ['name' => 'Closed Lost', 'order' => 5, 'probability' => 0],
    ],
]);

// Get all opportunities in a pipeline
ium()->crm()->pipelines()->find('sales-pipeline')
    ->opportunities();

// Filter by stage
ium()->crm()->pipelines()->find('sales-pipeline')
    ->opportunities(stage: 'negotiation');

Activities

Activities record every customer interaction and allow your team to schedule future follow-ups. Link them to contacts and opportunities for full context.

Log & Schedule

// Log a past activity
ium()->crm()->activities()->log([
    'type' => 'call', // call | email | meeting | task | note
    'contact_id' => $contact->id,
    'opportunity_id' => $opp->id,
    'note' => 'Interested in offer, requesting discount',
    'duration' => 15,
    'occurred_at' => now(),
]);

// Schedule a future activity
ium()->crm()->activities()->schedule([
    'type' => 'meeting',
    'contact_id' => $contact->id,
    'opportunity_id' => $opp->id,
    'title' => 'Solution Presentation',
    'scheduled_at' => '2026-06-01 10:00:00',
    'assigned_to' => $userId,
]);

Query Activities

// Get activities for a contact
ium()->crm()->activities()
    ->forContact($contact)
    ->ofType('call')
    ->get();

// Get pending tasks for a user
ium()->crm()->activities()
    ->pending()
    ->assignedTo($userId)
    ->get();

Activity Types

TypeDescription
callPhone call
emailEmail
meetingMeeting
taskTask
noteNote

Segments

Segments group contacts dynamically using composable filter rules. Use them for targeted campaigns, bulk tagging, or integration with WMS stock-level data.

Create a Segment

ium()->crm()->segments()->create([
    'name' => 'Active VIP Customers',
    'filters' => [
        ['field' => 'tags', 'operator' => 'contains', 'value' => 'vip'],
        ['field' => 'last_order_at', 'operator' => 'greater_than', 'value' => now()->subDays(30)],
        ['field' => 'total_spent', 'operator' => 'greater_than', 'value' => 10000],
    ],
]);

// Get contacts in segment
ium()->crm()->segments()->find('SEG-001')->contacts();

// Bulk tag / untag
ium()->crm()->segments()->find('SEG-001')->tag('promotion-eligible');
ium()->crm()->segments()->find('SEG-001')->untag('promotion-eligible');

Supported Filter Operators

  • contains — Field contains value
  • equals — Exact match
  • greater_than — Numeric / date comparison
  • less_than — Numeric / date comparison
  • in — Value in array

Reports

Built-in reporting covers pipeline performance, team activity, lead source attribution, and revenue forecasting — all via a fluent date-ranged query builder.

Pipeline Report

$report = ium()->crm()->reports()->pipeline('sales-pipeline')
    ->from('2026-01-01')
    ->to('2026-06-30')
    ->get();

// $report->total_value    → 250,000 SAR
// $report->won_count      → 12
// $report->lost_count     → 5
// $report->win_rate       → 70%
// $report->avg_deal_size  → 20,833 SAR
// $report->avg_cycle_days → 45

Activity & Lead Source Reports

// Team activity report
ium()->crm()->reports()->activities()
    ->forUser($userId)
    ->from('2026-05-01')
    ->to('2026-05-31')
    ->get();

// Lead source attribution
ium()->crm()->reports()->leadSources()
    ->from('2026-01-01')
    ->to('2026-06-30')
    ->get();

// Revenue forecast
ium()->crm()->reports()->forecast()
    ->pipeline('sales-pipeline')
    ->quarter('Q3-2026')
    ->get();

OMS & PIM Integration

IUM-CRM integrates natively with IUM-OMS and IUM-PIM. Access order history, spending statistics, and product suggestions directly from the CRM fluent API.

Order History & Product Suggestions

// Get customer order history (OMS)
ium()->crm()->contacts()->find('CON-001')
    ->orders()
    ->get();

// Spending statistics
ium()->crm()->contacts()->find('CON-001')
    ->orders()
    ->stats();

// Suggest products from PIM
ium()->crm()->contacts()->find('CON-001')
    ->suggestProducts(limit: 5);

Integration Map

CRM ModuleIntegrates WithPurpose
ContactsOMSLink customer to orders
LeadsPIMShow products to prospects
OpportunitiesPIMAttach products to deals
OpportunitiesOMSLink won deals to orders
SegmentsWMSTarget offers by stock levels

Full Method Chaining

// From lead creation to fulfilled opportunity
ium()->crm()
    ->leads()->create([
        'contact_id' => $contact->id,
        'source' => 'website',
        'score' => 80,
    ])
    ->qualify([
        'budget' => 50000,
        'timeline' => 'Q3-2026',
    ])
    ->convert(pipeline: 'sales-pipeline')
    ->moveTo(stage: 'proposal')
    ->attachProducts([
        ['sku' => 'PKG-ENTERPRISE', 'qty' => 1, 'price' => 50000],
    ]);