Skip to main content

Overview

Cash adjustments capture income or outflow transactions broken down by tender type (cash, card, transfer). Each adjustment contains a header with metadata and one or more lines representing individual tender amounts.

Adjustment Types

From CashAdjustment.php:30-33:
public const TYPE_EXTERNAL_IMPORT = 'EXTERNAL_IMPORT';
public const TYPE_CORRECTION = 'CORRECTION';
TypePurposeWhen to Use
EXTERNAL_IMPORTDaily sales totals from external POSEnd-of-day import from another system
CORRECTIONManual adjustments to fix variancesPhysical count doesn’t match expected balance

Direction

From CashAdjustment.php:35-38:
public const DIRECTION_INFLOW = 'INFLOW';
public const DIRECTION_OUTFLOW = 'OUTFLOW';
DirectionDescriptionEffect on Balance
INFLOWIncome or depositsIncreases closing balance
OUTFLOWWithdrawals or transfers outDecreases closing balance
Most adjustments are INFLOW (daily sales). Use OUTFLOW for vault transfers or withdrawals.

Adjustment Structure

Header Fields

FieldTypeDescription
cash_session_idForeign KeyLinks to the daily session
source_systemStringExternal system name (e.g., “ExternalPOS”)
typeEnumEXTERNAL_IMPORT or CORRECTION
directionEnumINFLOW or OUTFLOW
notesTextAdditional context or reason
posted_byForeign KeyUser who approved (nullable until posted)
posted_atTimestampWhen finalized (nullable until posted)
metaJSONExtra metadata (batch ID, external reference)

Line Fields

From CashAdjustmentLine.php:15-24:
FieldTypeRequiredDescription
cash_adjustment_idForeign KeyYesLinks to adjustment header
tender_typeEnumYesCASH, CARD, or TRANSFER
amountDecimalYesTransaction amount (4 decimal places)
currencyStringYesCurrency code (default: MXN)
card_terminal_idForeign KeyIf CARDLinks to terminal
bank_account_idForeign KeyIf TRANSFERLinks to bank account
referenceStringNoExternal batch or transaction ID
metaJSONNoTips, fees, or other data

Tender Type Constants

From CashAdjustmentLine.php:32-37:
public const TENDER_CASH = 'CASH';
public const TENDER_CARD = 'CARD';
public const TENDER_TRANSFER = 'TRANSFER';

Create an Adjustment

Endpoint

POST /api/v1/cash-adjustments

Request Example

From CreateCashAdjustmentController.php:38-52:
{
  "cash_session_id": 1,
  "type": "EXTERNAL_IMPORT",
  "direction": "INFLOW",
  "source_system": "ExternalPOS",
  "notes": "End-of-day import for 2026-03-06",
  "lines": [
    {
      "tender_type": "CASH",
      "amount": 1250.00,
      "currency": "MXN"
    },
    {
      "tender_type": "CARD",
      "amount": 3400.00,
      "currency": "MXN",
      "card_terminal_id": 2,
      "reference": "BATCH-2026-03-06-001"
    },
    {
      "tender_type": "TRANSFER",
      "amount": 800.00,
      "currency": "MXN",
      "bank_account_id": 1,
      "reference": "TXN-XYZ123"
    }
  ],
  "meta": {
    "external_batch_id": "BATCH-2026-03-06",
    "imported_at": "2026-03-06T22:30:00Z"
  }
}
  • When tender_type is CARD, card_terminal_id is required
  • When tender_type is TRANSFER, bank_account_id is required
  • When tender_type is CASH, both fields should be null

Response

{
  "message": "Adjustment created successfully",
  "data": {
    "id": 1,
    "cash_session_id": 1,
    "type": "EXTERNAL_IMPORT",
    "direction": "INFLOW",
    "source_system": "ExternalPOS",
    "posted_by": null,
    "posted_at": null,
    "lines": [
      {
        "id": 1,
        "tender_type": "CASH",
        "amount": "1250.0000",
        "currency": "MXN"
      },
      {
        "id": 2,
        "tender_type": "CARD",
        "amount": "3400.0000",
        "card_terminal_id": 2
      },
      {
        "id": 3,
        "tender_type": "TRANSFER",
        "amount": "800.0000",
        "bank_account_id": 1
      }
    ]
  }
}

Post an Adjustment

Posting finalizes the adjustment, making it immutable and including it in the session’s closing balance.

Endpoint

POST /api/v1/cash-adjustments/{id}/post
From PostCashAdjustmentController.php:34-51:
// Post the adjustment
const response = await api.post(`/cash-adjustments/${adjustmentId}/post`);

// Response includes posted_by and posted_at
{
  "message": "Adjustment posted successfully",
  "data": {
    "id": 1,
    "posted_by": 5,
    "posted_at": "2026-03-06T23:00:00Z",
    "lines": [...]
  }
}
Posting sets posted_by to the authenticated user and posted_at to the current timestamp.

Query Scopes

From CashAdjustment.php:66-110:
// Filter by status
CashAdjustment::posted()->get();
CashAdjustment::draft()->get();

// Filter by type
CashAdjustment::byType('EXTERNAL_IMPORT')->get();

// Filter by direction
CashAdjustment::byDirection('INFLOW')->get();
CashAdjustment::inflow()->get();
CashAdjustment::outflow()->get();

Helper Methods

Status Check

$adjustment->isPosted(); // Returns true if posted_at is not null

Total Amount

From CashAdjustment.php:123-126:
$adjustment->getTotalAmount(); // Sum of all line amounts

Relationships

Adjustment Header

Adjustment Lines

Workflow Diagram

Use Cases

Daily POS Import

Import end-of-day totals from external system:
{
  "cash_session_id": 1,
  "type": "EXTERNAL_IMPORT",
  "direction": "INFLOW",
  "source_system": "ExternalPOS",
  "lines": [
    { "tender_type": "CASH", "amount": 2500.00 },
    { "tender_type": "CARD", "amount": 5400.00, "card_terminal_id": 1 }
  ]
}

Variance Correction

Physical count shows $50 less than expected:
{
  "cash_session_id": 1,
  "type": "CORRECTION",
  "direction": "OUTFLOW",
  "notes": "Physical count variance - $50 short",
  "lines": [
    { "tender_type": "CASH", "amount": 50.00 }
  ]
}

Vault Transfer

Transfer excess cash to vault:
{
  "cash_session_id": 1,
  "type": "CORRECTION",
  "direction": "OUTFLOW",
  "notes": "Vault deposit - excess cash",
  "lines": [
    { "tender_type": "CASH", "amount": 1000.00 }
  ]
}

Best Practices

Use source_system and reference fields to track external batch IDs for reconciliation
Always provide detailed notes for corrections explaining the variance and resolution
Review all lines before posting. Once posted, adjustments become immutable.
Assign card lines to the correct terminal to track settlement by provider and terminal
Ensure all lines within an adjustment use the same currency (typically MXN)

Multi-Tender Example

Complete end-of-day import with all tender types:
const adjustment = await api.post('/cash-adjustments', {
  cash_session_id: sessionId,
  type: 'EXTERNAL_IMPORT',
  direction: 'INFLOW',
  source_system: 'ExternalPOS',
  notes: 'Daily close - Main Counter',
  lines: [
    // Cash tender
    {
      tender_type: 'CASH',
      amount: 1250.00,
      currency: 'MXN',
      meta: { counted_by: 'Cashier A' }
    },
    // Card via Terminal A
    {
      tender_type: 'CARD',
      amount: 3400.00,
      currency: 'MXN',
      card_terminal_id: 1,
      reference: 'BATCH-001',
      meta: { tips_included: 340.00 }
    },
    // Card via Terminal B
    {
      tender_type: 'CARD',
      amount: 1200.00,
      currency: 'MXN',
      card_terminal_id: 2,
      reference: 'BATCH-002'
    },
    // Bank transfer
    {
      tender_type: 'TRANSFER',
      amount: 800.00,
      currency: 'MXN',
      bank_account_id: 1,
      reference: 'TXN-XYZ789'
    }
  ],
  meta: {
    external_batch_id: 'EOD-2026-03-06',
    imported_at: new Date().toISOString()
  }
});

// Post after review
await api.post(`/cash-adjustments/${adjustment.data.id}/post`);

Error Handling

{
  "message": "Validation error",
  "errors": {
    "lines.1.card_terminal_id": [
      "The card_terminal_id field is required when tender_type is CARD"
    ]
  }
}

Next Steps

Cash Sessions

Learn how adjustments affect session balances

Cash Expenses

Record operational expenses during sessions

Build docs developers (and LLMs) love