v1.0.0

Customer Relationship Management

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'      => 'ahmed@example.com',
    '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'],
]);

Retrieve Related Data

// 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]);

Lead Statuses

  • new — Just created
  • contacted — Reached out
  • qualified — Meets criteria
  • disqualified — Not a fit

Lead Sources

  • 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

call — Phone call email — Email meeting — Meeting task — Task note — Note

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
// $stats->total_spent   → 75,000 SAR
// $stats->order_count   → 8
// $stats->last_order_at → 2026-04-15
ium()->crm()->contacts()->find('CON-001')
    ->orders()
    ->stats();

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

Integration Map

CRM Module Integrates With Purpose
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],
    ]);