libra/docs/stories/story-2.2-company-client-ac...

8.8 KiB

Story 2.2: Company/Corporate Client Account Management

Epic Reference

Epic 2: User Management System

User Story

As an admin, I want to create, view, edit, and manage company/corporate client accounts, So that I can serve corporate clients with their unique data requirements.

Story Context

Existing System Integration

  • Integrates with: users table (company-specific fields), admin_logs table
  • Technology: Livewire Volt (class-based), Flux UI forms, Pest tests
  • Follows pattern: Same CRUD pattern as Story 2.1 Individual Clients
  • Key Files to Create/Modify:
    • resources/views/livewire/admin/users/company/ - Volt components (index, create, edit, show)
    • app/Models/User.php - Add scopeCompany() method
    • resources/lang/ar/messages.php - Arabic translations
    • resources/lang/en/messages.php - English translations
    • tests/Feature/Admin/CompanyClientTest.php - Feature tests

Acceptance Criteria

Create Company Client

  • Form with required fields:
    • Company Name (required)
    • Company Registration Number (required, unique)
    • Contact Person Name (required)
    • Contact Person ID (required)
    • Email Address (required, unique)
    • Phone Number (required)
    • Password (admin-set, required)
    • Preferred Language (Arabic/English dropdown)
  • Validation for all required fields
  • Duplicate email/registration number prevention
  • Success message on creation

Multiple Contact Persons (OUT OF SCOPE)

Note: Multiple contact persons support is deferred to a future enhancement story. This story implements single contact person stored directly on the users table. The contact_persons table migration in Technical Notes is for reference only if this feature is later prioritized.

List View

  • Display all company clients (user_type = 'company')
  • Columns: Company Name, Contact Person, Email, Reg #, Status, Created Date
  • Pagination (10/25/50 per page)
  • Default sort by created date

Search & Filter

  • Search by company name, email, or registration number
  • Filter by status (active/deactivated/all)
  • Real-time search with debounce

Edit Company

  • Edit all company information
  • Update contact person details
  • Validation same as create
  • Success message on update

View Company Profile

  • Display all company information (including contact person details)
  • Show consultation history summary
  • Show timeline history summary

Quality Requirements

  • Bilingual form labels and messages
  • Proper form validation
  • Audit log entries for all operations
  • Tests for CRUD operations

Technical Notes

User Model Scope

public function scopeCompany($query)
{
    return $query->where('user_type', 'company');
}

Database Fields for Company

users table:
  - company_name (nullable, required for company type)
  - company_registration (nullable, unique when not null)
  - contact_person_name (nullable, required for company)
  - contact_person_id (nullable, required for company)

Future Reference: Separate Contact Persons Table

Note: This migration is NOT part of this story. It is preserved here for future reference if multiple contact persons feature is prioritized.

// contact_persons migration (FUTURE - NOT IN SCOPE)
Schema::create('contact_persons', function (Blueprint $table) {
    $table->id();
    $table->foreignId('user_id')->constrained()->cascadeOnDelete();
    $table->string('name');
    $table->string('national_id');
    $table->string('phone')->nullable();
    $table->string('email')->nullable();
    $table->boolean('is_primary')->default(false);
    $table->timestamps();
});

Validation Rules

public function rules(): array
{
    return [
        'company_name' => ['required', 'string', 'max:255'],
        'company_registration' => ['required', 'string', 'unique:users,company_registration'],
        'contact_person_name' => ['required', 'string', 'max:255'],
        'contact_person_id' => ['required', 'string'],
        'email' => ['required', 'email', 'unique:users,email'],
        'phone' => ['required', 'string'],
        'password' => ['required', 'string', 'min:8'],
        'preferred_language' => ['required', 'in:ar,en'],
    ];
}

Volt Component for Create

Follow the same component structure as Story 2.1 (docs/stories/story-2.1-individual-client-account-management.md).

<?php

use App\Models\User;
use App\Models\AdminLog; // Assumes AdminLog model exists from Story 1.1
use Livewire\Volt\Component;
use Illuminate\Support\Facades\Hash;

new class extends Component {
    public string $company_name = '';
    public string $company_registration = '';
    public string $contact_person_name = '';
    public string $contact_person_id = '';
    public string $email = '';
    public string $phone = '';
    public string $password = '';
    public string $preferred_language = 'ar';

    public function create(): void
    {
        $validated = $this->validate();

        $user = User::create([
            ...$validated,
            'user_type' => 'company',
            'name' => $this->company_name, // For display purposes
            'password' => Hash::make($this->password),
            'status' => 'active',
        ]);

        // Log action (same pattern as Story 2.1)
        AdminLog::create([
            'admin_id' => auth()->id(),
            'action_type' => 'create',
            'target_type' => 'user',
            'target_id' => $user->id,
            'new_values' => $user->only(['company_name', 'email', 'company_registration']),
            'ip_address' => request()->ip(),
        ]);

        // Send welcome email (depends on Story 2.5)

        session()->flash('success', __('messages.company_created'));
        $this->redirect(route('admin.users.index'));
    }
};

Testing Requirements

Test Approach

  • Feature tests using Pest with Volt::test() for Livewire components
  • Factory-based test data generation

Key Test Scenarios

Create Company Client

  • Successfully create company with all valid required fields
  • Validation fails when required fields are missing
  • Validation fails for duplicate email address
  • Validation fails for duplicate company registration number
  • Preferred language defaults to Arabic when not specified
  • Audit log entry created on successful creation

List View

  • List displays only company type users (excludes individual/admin)
  • Pagination works correctly (10/25/50 per page)
  • Default sort is by created date descending

Search & Filter

  • Search by company name returns correct results
  • Search by email returns correct results
  • Search by registration number returns correct results
  • Filter by active status works
  • Filter by deactivated status works
  • Combined search and filter works correctly

Edit Company

  • Successfully update company information
  • Validation fails for duplicate email (excluding current record)
  • Validation fails for duplicate registration number (excluding current record)
  • Audit log entry created on successful update

View Profile

  • Profile displays all company information correctly
  • Consultation history summary displays (empty state if none)
  • Timeline history summary displays (empty state if none)

Bilingual Support

  • Form labels display correctly in Arabic
  • Form labels display correctly in English
  • Validation messages display in user's preferred language

Definition of Done

  • Create company client form works
  • List view displays all company clients
  • Search and filter functional
  • Edit company works with validation
  • View profile shows complete information
  • Duplicate prevention works
  • Audit logging implemented
  • Bilingual support complete
  • Tests pass for all CRUD operations
  • Code formatted with Pint

Dependencies

  • Epic 1: Authentication system, database schema
  • Story 1.1: Database schema must include the following columns in users table:
    • user_type (enum: 'individual', 'company', 'admin')
    • status (enum: 'active', 'deactivated')
    • phone (string)
    • preferred_language (enum: 'ar', 'en')
    • company_name (nullable string)
    • company_registration (nullable string, unique when not null)
    • contact_person_name (nullable string)
    • contact_person_id (nullable string)
    • national_id (nullable string, unique when not null)
  • Story 2.1: CRUD patterns established in docs/stories/story-2.1-individual-client-account-management.md

Risk Assessment

  • Primary Risk: Complex contact persons relationship
  • Mitigation: Start simple (single contact), enhance later if needed
  • Rollback: Use simple fields on users table

Estimation

Complexity: Medium Estimated Effort: 4-5 hours