Overview
TheReceivableService manages accounts receivable (CxC - Cuentas por Cobrar) for the ERP system. It handles the creation of receivables from credit sales, tracks payment status, and generates corresponding accounting journal entries.
Namespace: App\Services\Accounting\Receivable\ReceivableService
Location: app/Services/Accounting/Receivable/ReceivableService.php
Dependencies
The service is constructed with:JournalEntryService- Creates accounting journal entries for receivables
Methods
createReceivable()
Creates a new accounts receivable record with corresponding accounting journal entry.Receivable data with the following structure:
Returns the created Receivable model instance
- Retrieve Client - Fetches client record
- Determine Account - Uses (in priority order):
- Client’s specific accounting account (
client.accounting_account_id) - Provided
accounting_account_idfrom data - Default Accounts Receivable account (code 1.1.02)
- Client’s specific accounting account (
- Create Journal Entry - Creates posted entry:
- Debit: Accounts Receivable Account (asset increase)
- Credit: Income Account 4.1 (revenue recognition)
- Create Receivable Record - Creates receivable with:
- Initial status:
'unpaid' current_balance=total_amount(no payments yet)- Links to journal entry and client
- Initial status:
SaleService for credit sales, not called directly from controllers.
Example Usage
cancelReceivable()
Cancels an accounts receivable record. Only allowed if no payments have been applied.The Receivable model instance to cancel
Returns
true if cancellation was successful- Returns
trueimmediately if already cancelled - Throws exception if
current_balance < total_amount(indicates payments exist) - Only unpaid receivables (full balance remaining) can be cancelled
- Check if already cancelled (return true if so)
- Verify no payments applied (
current_balance === total_amount) - Update status to
'cancelled' - Set
current_balanceto 0
SaleService.cancel()).
Example Usage
updateStatusBasedOnBalance()
Updates the receivable status based on its current balance. This method is required byPaymentService when processing payments.
The Receivable model instance to update
current_balance <= 0→ Status:'paid'current_balance < total_amount→ Status:'partial'current_balance >= total_amount→ Status:'unpaid'
Example Usage
Protected Methods
getAccountIdByCode()
Helper method to retrieve accounting account ID by account code.Accounting account code (e.g., ‘1.1.02’, ‘4.1’)
Returns the accounting account ID, or throws exception if not found
ReceivableService.php:103-106
Receivable Model Constants
Accounting Integration
Journal Entry for Receivable Creation
When a receivable is created, the service generates this accounting entry:Exception Handling
Cannot Cancel with Payments
Cannot Cancel with Payments
Exception:
"No se puede anular una factura con abonos."Cause: Attempting to cancel a receivable that has received partial or full paymentResolution:- Check
current_balance === total_amountbefore attempting cancellation - If payments exist, use a different business process (credit notes, refunds, etc.)
Client Not Found
Client Not Found
Cause: Invalid
client_id provided to createReceivable()Resolution: Verify client exists before creating receivableMissing Account Configuration
Missing Account Configuration
Cause: Income Account (4.1) or default Receivable Account (1.1.02) not foundResolution: Ensure required accounting accounts are configured in the system
Database Transaction Safety
BothcreateReceivable() and cancelReceivable() methods wrap operations in database transactions using DB::transaction(). This ensures:
- Journal entries and receivable records are created atomically
- Failures trigger complete rollback
- Data consistency is maintained
Receivable Lifecycle
Payment Processing
As payments are applied:
- Balance decreases
- Status updates via
updateStatusBasedOnBalance() - Transitions: unpaid → partial → paid
Integration Points
Used By
- SaleService - Creates receivables for credit sales, cancels receivables on sale cancellation
- PaymentService - Calls
updateStatusBasedOnBalance()after applying payments - InvoiceController - May create standalone receivables for invoicing
Uses
- JournalEntryService - Creates accounting entries for receivable transactions
- Client Model - Retrieves client information and specific accounting accounts
- AccountingAccount Model - Retrieves receivable and income account IDs
Related Models
- Receivable Model - Receivable entity
- Client Model - Client information
- JournalEntry Model - Associated accounting entries
- Payment Model - Payment applications
Best Practices
Use Service Methods
Always use service methods rather than creating receivables directly to ensure accounting integrity
Check Balance Before Cancel
Verify
current_balance === total_amount before attempting cancellationUpdate Status After Payments
Always call
updateStatusBasedOnBalance() after modifying current_balanceUse References
Always populate
reference_type and reference_id to maintain audit trail to source documents