aureuserp/aureuserp · error · Exception

accounts::account-manager.post-action-validate.currency-arch

Error message

accounts::account-manager.post-action-validate.currency-archived

What it means

Companion check to the journal guard in MoveWorkflow's post-action validation: it throws when `$move->currency` is null. Debits, credits, and exchange-rate handling all depend on a live currency record, so a move whose currency_id references an archived, deactivated, or missing currency cannot be posted.

Source

Thrown at plugins/webkul/accounts/src/Services/MoveWorkflow.php:283

        if (in_array($move->state, [MoveState::POSTED, MoveState::CANCEL])) {
            throw new Exception(__('accounts::account-manager.post-action-validate.draft-state-required'));
        }

        if ($move->lines->isEmpty()) {
            throw new Exception(__('accounts::account-manager.post-action-validate.lines-required'));
        }

        if ($move->lines->some(fn (MoveLine $line) => $line->account && $line->account->deprecated)) {
            throw new Exception(__('accounts::account-manager.post-action-validate.account-deprecated'));
        }

        if (! $move->journal) {
            throw new Exception(__('accounts::account-manager.post-action-validate.journal-archived'));
        }

        if (! $move->currency) {
            throw new Exception(__('accounts::account-manager.post-action-validate.currency-archived'));
        }
    }

    protected function assertNotExchangeDifference(AccountMove $move): void
    {
        $partialIds = PartialReconcile::where('exchange_move_id', $move->id)->pluck('id')->unique();

        $fullIds = FullReconcile::where('exchange_move_id', $move->id)->pluck('id')->unique();

        if ($partialIds->merge($fullIds)->isNotEmpty()) {
            throw new Exception('You cannot reset to draft an exchange difference journal entry.');
        }
    }

    protected function stampLineStates(AccountMove $move, MoveState $state): void
    {
        foreach ($move->lines as $line) {
            $line->update(['parent_state' => $state]);

View on GitHub (pinned to bd7cbeeb0c)

Solutions

  1. Re-enable the archived currency so $move->currency resolves
  2. Reassign the move to an active currency: $move->update(['currency_id' => $activeCurrency->id]) and re-check amounts
  3. Fix imported currency_id values so each matches an existing currencies record
  4. Guard before posting: if (! $move->currency) surface a validation error to the user instead of posting

Example fix

// before
app(MoveWorkflow::class)->post($move); // throws currency-archived when currency is null

// after
$move->loadMissing('currency');
if (! $move->currency) {
    $move->update(['currency_id' => $companyCurrency->id]);
}
app(MoveWorkflow::class)->post($move);
Defensive patterns

Strategy: validation

Validate before calling

$move->loadMissing('currency');
if (! $move->currency) {
    throw new RuntimeException("Move {$move->id} has no live currency; set currency_id before posting.");
}
app(MoveWorkflow::class)->post($move);

Type guard

function hasLiveCurrency(AccountMove $move): bool
{
    $move->loadMissing('currency');

    return $move->currency !== null;
}

Prevention

When it happens

Trigger: Posting or validating an AccountMove whose currency_id references a deactivated or deleted currency; moves created before the currency was disabled; imports that stored a currency reference with no matching currencies row.

Common situations: A foreign currency is disabled while invoices in that currency are still in draft; multi-currency ledgers consolidated and currency records archived; seeded data referencing currency IDs that were later wiped.

Related errors


AI-assisted analysis of aureuserp/aureuserp@bd7cbeeb0c (2026-08-21). Data as JSON: /api/errors/647ad454ad4e130e. Report an issue: GitHub.