azaharizaman/nexus-procurement

Framework-agnostic procurement management package for purchase requisitions, purchase orders, goods receipts, and 3-way matching

Maintainers

👁 azaharizaman

Package info

github.com/azaharizaman/nexus-procurement

pkg:composer/azaharizaman/nexus-procurement

Statistics

Installs: 2

Dependents: 3

Suggesters: 1

Stars: 0

Open Issues: 0

v0.1.0-alpha1 2026-05-05 02:28 UTC

Requires

Requires (Dev)

None

Suggests

None

Provides

None

Conflicts

None

Replaces

None

MIT 8fc0d3fdb927b77c6b0be7af38bcec89687bab65

This package is auto-updated.

Last update: 2026-06-05 03:16:32 UTC


README

Framework-agnostic procurement management package for Nexus ERP

The Procurement package provides a comprehensive, pure PHP solution for purchase requisitions, purchase orders, goods receipts, 3-way matching, and vendor quote management. It follows strict contract-driven design principles and integrates seamlessly with the Nexus monorepo architecture.

Features

  • Pure PHP 8.3+ - No framework dependencies in core logic
  • Contract-Driven - All data structures and operations defined via interfaces
  • Purchase Requisition Management - Complete workflow from draft to approval to PO conversion
  • Purchase Order Processing - Create POs from requisitions or directly with budget validation
  • Goods Receipt Notes (GRN) - Record and validate received goods against purchase orders
  • 3-Way Matching Engine - Validate Invoice-PO-GRN alignment (<500ms for 100 lines)
  • Vendor Quote Management - RFQ process and quote comparison
  • Segregation of Duties - Requester ≠ Approver ≠ Receiver ≠ Payment Authorizer
  • Budget Controls - PO cannot exceed requisition by >10% without re-approval
  • Multi-Tenant - Tenant-scoped requisitions, POs, and GRNs

Installation

composer require azaharizaman/nexus-procurement:"*@dev"

Architecture

Package Structure

packages/Procurement/
├── src/
│ ├── Contracts/ # 19 Interfaces
│ │ ├── ProcurementManagerInterface.php
│ │ ├── RequisitionInterface.php
│ │ ├── RequisitionLineInterface.php
│ │ ├── RequisitionRepositoryInterface.php
│ │ ├── PurchaseOrderInterface.php
│ │ ├── PurchaseOrderLineInterface.php
│ │ ├── PurchaseOrderRepositoryInterface.php
│ │ ├── GoodsReceiptNoteInterface.php
│ │ ├── GoodsReceiptLineInterface.php
│ │ ├── GoodsReceiptRepositoryInterface.php
│ │ ├── VendorQuoteInterface.php
│ │ ├── VendorQuoteRepositoryInterface.php
│ │ └── ... (7 analytics repository interfaces)
│ ├── Services/ # 6 Business Logic Services
│ │ ├── ProcurementManager.php
│ │ ├── RequisitionManager.php
│ │ ├── PurchaseOrderManager.php
│ │ ├── GoodsReceiptManager.php
│ │ ├── MatchingEngine.php
│ │ └── VendorQuoteManager.php
│ └── Exceptions/ # 10 Domain Exceptions
│ ├── ProcurementException.php
│ ├── RequisitionNotFoundException.php
│ ├── PurchaseOrderNotFoundException.php
│ ├── GoodsReceiptNotFoundException.php
│ ├── InvalidRequisitionDataException.php
│ ├── InvalidRequisitionStateException.php
│ ├── InvalidPurchaseOrderDataException.php
│ ├── InvalidGoodsReceiptDataException.php
│ ├── BudgetExceededException.php
│ └── UnauthorizedApprovalException.php
├── composer.json
├── LICENSE
└── README.md

Core Principles

  1. Logic in Packages, Implementation in Applications

    • Package defines what (interfaces, services, value objects)
    • Application defines how (Eloquent models, repositories, migrations)
  2. Framework Agnostic

    • Zero Laravel dependencies in src/
    • No Illuminate\* classes
    • No Eloquent models
    • No database queries
  3. Dependency Injection

    • Constructor injection for all dependencies
    • Interface-based dependencies only

Usage Examples

Create Purchase Requisition

use Nexus\Procurement\Contracts\ProcurementManagerInterface;

$procurement = app(ProcurementManagerInterface::class);

$requisition = $procurement->createRequisition(
 tenantId: 'tenant-001',
 requesterId: 'user-123',
 data: [
 'number' => 'REQ-2025-001',
 'description' => 'Office supplies for Q1',
 'department' => 'Administration',
 'lines' => [
 [
 'item_code' => 'PAPER-A4',
 'description' => 'A4 Paper 500 sheets',
 'quantity' => 10,
 'unit' => 'box',
 'estimated_unit_price' => 25.00,
 ],
 ],
 ]
);

Approve Requisition (with Segregation of Duties)

use Nexus\Procurement\Exceptions\UnauthorizedApprovalException;

try {
 $approvedRequisition = $procurement->approveRequisition(
 requisitionId: $requisition->getId(),
 approverId: 'manager-456' // Must NOT be the requester
 );
} catch (UnauthorizedApprovalException $e) {
 // BUS-PRO-0095 violation: Requester tried to approve own requisition
}

Convert Requisition to Purchase Order

use Nexus\Procurement\Exceptions\BudgetExceededException;

try {
 $po = $procurement->convertRequisitionToPO(
 tenantId: 'tenant-001',
 requisitionId: $requisition->getId(),
 creatorId: 'buyer-789',
 poData: [
 'number' => 'PO-2025-001',
 'vendor_id' => 'vendor-xyz',
 'lines' => [
 [
 'requisition_line_id' => $requisition->getLines()[0]->getId(),
 'quantity' => 10,
 'unit_price' => 24.50, // Within 10% of estimate
 'unit' => 'box',
 'item_code' => 'PAPER-A4',
 'description' => 'A4 Paper 500 sheets',
 ],
 ],
 ]
 );
} catch (BudgetExceededException $e) {
 // PO exceeds requisition by more than 10%
}

Record Goods Receipt

$grn = $procurement->recordGoodsReceipt(
 tenantId: 'tenant-001',
 poId: $po->getId(),
 receiverId: 'warehouse-clerk-001', // Must NOT be PO creator
 receiptData: [
 'number' => 'GRN-2025-001',
 'received_date' => '2025-11-20',
 'lines' => [
 [
 'po_line_reference' => 'PO-2025-001-L001',
 'quantity_received' => 10, // Cannot exceed PO quantity
 'unit' => 'box',
 ],
 ],
 ]
);

Three-Way Matching

$matchResult = $procurement->performThreeWayMatch(
 poLine: $poLine,
 grnLine: $grnLine,
 invoiceLineData: [
 'quantity' => 10,
 'unit_price' => 24.50,
 'line_total' => 245.00,
 ]
);

if ($matchResult['matched']) {
 echo "✅ Auto-approved: {$matchResult['recommendation']}";
} else {
 echo "⚠️ Manual review: {$matchResult['recommendation']}";
 print_r($matchResult['discrepancies']);
}

Business Rules

Integration Points

  • Nexus\Payable: Provides PO and GRN data for 3-way matching and handles vendor bill payments
  • Nexus\Inventory: Manages stock levels, which are updated upon successful goods receipt
  • Nexus\Finance: Receives journal entries for all procurement-related financial events
  • Nexus\Budget: Provides budget data for validation against requisitions and purchase orders
  • Nexus\Workflow: Requisition approval workflows and multi-step approval processes
  • Nexus\Uom: Unit of measurement validation
  • Nexus\Currency: Multi-currency support
  • Nexus\AuditLogger: Comprehensive change tracking
  • Nexus\Sequencing: Auto-numbering for REQ/PO/GRN

Exception Handling

All domain exceptions extend ProcurementException:

use Nexus\Procurement\Exceptions\{
 RequisitionNotFoundException,
 PurchaseOrderNotFoundException,
 GoodsReceiptNotFoundException,
 InvalidRequisitionDataException,
 InvalidRequisitionStateException,
 InvalidPurchaseOrderDataException,
 InvalidGoodsReceiptDataException,
 BudgetExceededException,
 UnauthorizedApprovalException
};

try {
 $requisition = $procurement->getRequisition($requisitionId);
} catch (RequisitionNotFoundException $e) {
 // Handle requisition not found
}

try {
 $approved = $procurement->approveRequisition($id, $approverId);
} catch (UnauthorizedApprovalException $e) {
 // Handle unauthorized approval attempt
}

Performance

  • 3-Way Matching: <500ms for 100-line invoices (PER-PRO-0341)
  • Requisition Creation: <200ms with eager loading
  • PO Generation: <300ms with budget validation

Requirements Addressed

This package addresses all requirements in REQUIREMENTS.md:

  • ✅ BUS-PRO-0041 to BUS-PRO-0124: 15 Business requirements
  • ✅ FUN-PRO-0235 to FUN-PRO-0271: 7 Functional requirements
  • ✅ PER-PRO-0327 to PER-PRO-0353: 5 Performance requirements
  • ✅ REL-PRO-0389 to REL-PRO-0407: 4 Reliability requirements
  • ✅ SEC-PRO-0441 to SEC-PRO-0470: 6 Security requirements
  • ✅ USE-PRO-0508 to USE-PRO-0548: 7 User stories

Total: 44 requirements

Testing

Package tests use mocks for all repository implementations:

use Nexus\Procurement\Services\ProcurementManager;
use Nexus\Procurement\Contracts\RequisitionRepositoryInterface;
use PHPUnit\Framework\TestCase;

class ProcurementManagerTest extends TestCase
{
 public function test_create_requisition(): void
 {
 $mockRepo = $this->createMock(RequisitionRepositoryInterface::class);
 $mockRepo->expects($this->once())
 ->method('create')
 ->willReturn($this->createMock(RequisitionInterface::class));
 
 $manager = new ProcurementManager($mockRepo, ...);
 // ... test logic
 }
}

📖 Documentation

Package Documentation

Additional Resources

  • IMPLEMENTATION_SUMMARY.md - Implementation progress, metrics, and key design decisions
  • REQUIREMENTS.md - All 44 requirements with status tracking
  • TEST_SUITE_SUMMARY.md - Test coverage metrics and test inventory
  • VALUATION_MATRIX.md - Package valuation metrics for funding assessment
  • See root ../../ARCHITECTURE.md for overall system architecture
  • See ../../docs/NEXUS_PACKAGES_REFERENCE.md for package ecosystem reference

License

MIT License. See LICENSE file for details.