### Install the package Source: https://github.com/nazbav/yii2-account-balance/wiki/tutorial-quick-start Use composer to add the package to your project. ```bash composer require nazbav/yii2-account-balance --prefer-dist ``` -------------------------------- ### Run Full Test Suite Source: https://github.com/nazbav/yii2-account-balance/blob/master/docs/README.md Execute the complete test suite for the library using phpunit. Ensure all tests pass to maintain code quality. ```bash phpunit -c phpunit.xml.dist ``` -------------------------------- ### Configure Secure Library Settings Source: https://github.com/nazbav/yii2-account-balance/wiki/explanation-fraud-controls Defines the recommended configuration flags to enforce strict validation, prevent negative balances, and ensure operation idempotency. ```php 'requirePositiveAmount' => true, 'forbidTransferToSameAccount' => true, 'forbidNegativeBalance' => true, 'forbidDuplicateOperationId' => true, 'requireOperationId' => true, 'operationIdAttribute' => 'operationId', 'minimumAllowedBalance' => 0, 'accountBalanceAttribute' => 'balance', ``` -------------------------------- ### Implement Referral Program Rewards in PHP Source: https://context7.com/nazbav/yii2-account-balance/llms.txt Safely implement a referral program with pending rewards, anti-fraud checks, and phased activation. This involves creating pending accruals for both referrer and referred, followed by activation transfers and potential rollbacks if fraud is detected. ```php $manager = Yii::$app->balanceManager; // Шаг 1: Создание pending-начислений для обеих сторон $operationId = sprintf('ref:%d:%d:%s', $referrerUserId, $referredUserId, $programId); $manager->increase( ['userId' => $referrerUserId, 'walletType' => 'referral_pending'], $referrerReward, [ 'operationId' => $operationId, 'operationType' => 'referral_reward_pending', 'programId' => $programId, 'referrerUserId' => $referrerUserId, 'referredUserId' => $referredUserId, ] ); $manager->increase( ['userId' => $referredUserId, 'walletType' => 'referral_pending'], $referredReward, [ 'operationId' => $operationId . ':welcome', 'operationType' => 'referral_welcome_pending', 'programId' => $programId, 'referrerUserId' => $referrerUserId, 'referredUserId' => $referredUserId, ] ); // Шаг 2: После прохождения антифрод-проверок — активация $manager->transfer( ['userId' => $referrerUserId, 'walletType' => 'referral_pending'], ['userId' => $referrerUserId, 'walletType' => 'bonus_available'], $confirmedAmount, [ 'operationId' => $operationId . ':release', 'operationType' => 'referral_reward_release', ] ); // При выявлении фрода — откат $manager->revert($transactionId, [ 'operationType' => 'referral_rollback', 'reason' => 'Выявлены признаки мошенничества', ]); ``` -------------------------------- ### Recommended Production Configuration for Account Balance Source: https://github.com/nazbav/yii2-account-balance/wiki/reference-configuration This configuration profile is recommended for production environments. It enforces strict rules for account operations, such as disallowing negative balances and duplicate operation IDs. ```php 'autoCreateAccount' => false, 'requirePositiveAmount' => true, 'forbidTransferToSameAccount' => true, 'forbidNegativeBalance' => true, 'forbidDuplicateOperationId' => true, 'requireOperationId' => true, 'operationIdAttribute' => 'operationId', 'minimumAllowedBalance' => 0, 'accountBalanceAttribute' => 'balance', ``` -------------------------------- ### Basic Quality Control Commands Source: https://github.com/nazbav/yii2-account-balance/wiki/Home These commands are used for basic quality control of the library, including running tests, static analysis, and mutation testing. ```bash composer.phar test composer.phar analyse composer.phar test:mutation ``` -------------------------------- ### Quality Gate and Production Profile Source: https://github.com/nazbav/yii2-account-balance/blob/master/docs/reference-configuration.md Information on running quality gates and recommended configuration profile for production environments. ```APIDOC ## Minimum Quality Gate ```bash composer.phar test composer.phar analyse composer.phar test:mutation ``` ## Recommended Production Profile ```php 'autoCreateAccount' => false, 'requirePositiveAmount' => true, 'forbidTransferToSameAccount' => true, 'forbidNegativeBalance' => true, 'forbidDuplicateOperationId' => true, 'requireOperationId' => true, 'operationIdAttribute' => 'operationId', 'minimumAllowedBalance' => 0, 'accountBalanceAttribute' => 'balance', ``` If `autoCreateAccount=false`, the account must be created by a separate domain process. ``` -------------------------------- ### Configure Balance Rules Source: https://github.com/nazbav/yii2-account-balance/blob/master/docs/reference-configuration.md Set strict operational constraints such as minimum balance and negative balance prevention using the BalanceRules class. ```php use nazbavalance\BalanceRules; $manager->setBalanceRules(new BalanceRules( requirePositiveAmount: true, forbidTransferToSameAccount: true, forbidNegativeBalance: true, minimumAllowedBalance: 0, )); ``` -------------------------------- ### Enable Strict Mode Source: https://github.com/nazbav/yii2-account-balance/wiki/reference-configuration Quickly applies a strict configuration profile to the manager. ```php $manager->enableStrictMode(); // или $manager->setBalanceRules(BalanceRules::strict()); ``` -------------------------------- ### Define MySQL schema Source: https://github.com/nazbav/yii2-account-balance/wiki/tutorial-quick-start Create the required tables for accounts and transactions. ```sql CREATE TABLE balance_account ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, userId BIGINT UNSIGNED NOT NULL, walletType VARCHAR(64) NOT NULL, balance DECIMAL(19,4) NOT NULL DEFAULT 0, createdAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updatedAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uq_balance_account_user_wallet (userId, walletType) ) ENGINE=InnoDB; CREATE TABLE balance_transaction ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, createdAt DATETIME NOT NULL, accountId BIGINT UNSIGNED NOT NULL, extraAccountId BIGINT UNSIGNED NULL, operationId VARCHAR(128) NULL, amount DECIMAL(19,4) NOT NULL, data JSON NULL, PRIMARY KEY (id), KEY idx_balance_transaction_account_date (accountId, createdAt), KEY idx_balance_transaction_extra_account (extraAccountId), KEY idx_balance_transaction_account_operation (accountId, operationId), CONSTRAINT fk_balance_transaction_account FOREIGN KEY (accountId) REFERENCES balance_account(id) ) ENGINE=InnoDB; ``` -------------------------------- ### Configure Balance Rules in PHP Source: https://context7.com/nazbav/yii2-account-balance/llms.txt Set explicit balance operation rules or enable a strict profile. Use `BalanceRules` for fine-grained control over positive amounts, transfers to the same account, and negative balances. The strict profile offers a predefined set of restrictive rules. ```php use nazbav\balance\BalanceRules; // Явная настройка правил $manager->setBalanceRules(new BalanceRules( requirePositiveAmount: true, forbidTransferToSameAccount: true, forbidNegativeBalance: true, minimumAllowedBalance: 0, )); // Быстрый строгий профиль $manager->enableStrictMode(); // или эквивалент: $manager->setBalanceRules(BalanceRules::strict()); // Строгий профиль с нестандартным минимумом $manager->setBalanceRules(BalanceRules::strict(minimumAllowedBalance: -1000)); // Получение текущих правил $rules = $manager->getBalanceRules(); if ($rules->forbidNegativeBalance) { // логика при включённой защите от перерасхода } ``` -------------------------------- ### Account Handling Source: https://github.com/nazbav/yii2-account-balance/wiki/reference-behavior-matrix Describes how the system handles different types of account identifiers and creation scenarios. ```APIDOC ## Account Handling This section details how the system interacts with and manages accounts based on provided input. ### Account Input and Behavior | Account Input | Behavior | |---|---| | Scalar ID | Used directly as the account ID. | | Filter array | `findAccountId()` search is performed. | | Filter not found and `autoCreateAccount=true` | A new account is created via `createAccount()`. | | Filter not found and `autoCreateAccount=false` | `error.account_not_found_by_filter` exception is thrown. | | Filter contains only unknown schema attributes | `error.account_attributes_empty_after_filter` exception is thrown. | | Concurrent auto-creation of the same account (duplicate key) | The ID of the already created account is returned if the record is available for re-search. | ``` -------------------------------- ### Configure the balance manager component Source: https://github.com/nazbav/yii2-account-balance/blob/master/README.md Add the ManagerDb component to your application configuration to define database tables and security constraints. ```php use nazbavalance ransactions\ManagerDb; return [ 'components' => [ 'balanceManager' => [ 'class' => ManagerDb::class, 'db' => 'db', 'accountTable' => '{{%balance_account}}', 'transactionTable' => '{{%balance_transaction}}', 'accountLinkAttribute' => 'accountId', 'extraAccountLinkAttribute' => 'extraAccountId', 'accountBalanceAttribute' => 'balance', 'amountAttribute' => 'amount', 'dateAttribute' => 'createdAt', 'dataAttribute' => 'data', 'autoCreateAccount' => true, // Рекомендуемый профиль безопасности. 'requirePositiveAmount' => true, 'forbidTransferToSameAccount' => true, 'forbidNegativeBalance' => true, 'forbidDuplicateOperationId' => true, 'requireOperationId' => true, 'operationIdAttribute' => 'operationId', 'minimumAllowedBalance' => 0, ], ], ]; ``` -------------------------------- ### Increase Account Balance using Manager::increase() Source: https://context7.com/nazbav/yii2-account-balance/llms.txt Use the `increase()` method to credit an account. It accepts an account identifier or filter, an amount, and optional transaction data including `operationId` for idempotency. ```php $manager = Yii::$app->balanceManager; // Начисление бонусов за покупку $transactionId = $manager->increase( ['userId' => 1001, 'walletType' => 'bonus_available'], 500, [ 'operationId' => 'purchase:100500:bonus', 'operationType' => 'purchase_bonus', 'orderId' => 100500, ] ); // Начисление с учётом уровня лояльности $multiplier = match ($tier) { 'platinum' => 2.0, 'gold' => 1.5, 'silver' => 1.2, default => 1.0, }; $baseBonus = round($orderAmount * 0.05, 2); $finalBonus = round($baseBonus * $multiplier, 2); $manager->increase( ['userId' => $userId, 'walletType' => 'bonus_pending'], $finalBonus, [ 'operationId' => "order:" . $orderId . ":bonus_pending", 'operationType' => 'purchase_bonus_pending', 'tierAtPurchase' => $tier, 'multiplier' => $multiplier, ] ); ``` -------------------------------- ### Handle Manager Events Source: https://github.com/nazbav/yii2-account-balance/wiki/reference-configuration Attaches a listener to the before transaction creation event to inject custom metadata. ```php use nazbavalancealanceManager; use nazbavalancealanceTransactionEvent; $manager->on(Manager::EVENT_BEFORE_CREATE_TRANSACTION, static function (TransactionEvent $event): void { $event->transactionData['traceId'] = Yii::$app->request->headers->get('X-Trace-Id'); }); ``` -------------------------------- ### Architecture class diagram Source: https://github.com/nazbav/yii2-account-balance/blob/master/README.md Visual representation of the library's class hierarchy and interface implementation. ```mermaid classDiagram class ManagerInterface { +increase(account, amount, data) +decrease(account, amount, data) +transfer(from, to, amount, data) +revert(transactionId, data) +calculateBalance(account) } class Manager class ManagerDbTransaction class ManagerDb class ManagerActiveRecord class BalanceRules ManagerInterface <|.. Manager Manager <|-- ManagerDbTransaction ManagerDbTransaction <|-- ManagerDb ManagerDbTransaction <|-- ManagerActiveRecord Manager ..> BalanceRules ``` -------------------------------- ### Visualize operation flow with Mermaid Source: https://github.com/nazbav/yii2-account-balance/blob/master/README.md Sequence diagram illustrating the interaction between the external API, domain service, balance manager, and database. ```mermaid sequenceDiagram participant API as Внешний API participant Domain as Доменный сервис participant Manager as Balance Manager participant DB as MySQL API->>Domain: Запрос операции (operationId, account, amount) Domain->>Domain: Идемпотентность + лимиты + риск Domain->>Manager: increase/transfer/revert Manager->>DB: BEGIN Manager->>DB: INSERT balance_transaction Manager->>DB: UPDATE balance_account DB-->>Manager: COMMIT Manager-->>Domain: transactionId Domain-->>API: Результат ``` -------------------------------- ### Activate Referral Reward Source: https://github.com/nazbav/yii2-account-balance/wiki/howto-referral-program Transfer funds from the pending wallet to the available bonus wallet once the risk window has passed. ```php $manager->transfer( ['userId' => $referrerUserId, 'walletType' => 'referral_pending'], ['userId' => $referrerUserId, 'walletType' => 'bonus_available'], $confirmedAmount, [ 'operationId' => $operationId . ':release', 'operationType' => 'referral_reward_release', ] ); ``` -------------------------------- ### Catching Balance Operation Exceptions Source: https://context7.com/nazbav/yii2-account-balance/llms.txt Demonstrates how to handle InvalidArgumentException and InvalidConfigException when performing balance operations. The comments list specific error keys that may be encountered during execution. ```php use yii\base\InvalidArgumentException; use yii\base\InvalidConfigException; try { $manager->decrease(['userId' => 1, 'walletType' => 'bonus'], 100, [ 'operationId' => 'test:1', ]); } catch (InvalidArgumentException $e) { // Возможные ключи: // error.amount_not_numeric — сумма не число // error.amount_must_be_positive — сумма <= 0 // error.amount_must_be_finite — INF/-INF/NAN // error.transfer_same_account_forbidden — перевод на тот же счёт // error.transaction_not_found — транзакция для revert не найдена // error.insufficient_funds — недостаточно средств // error.operation_id_required — не передан operationId // error.operation_id_invalid — пустой operationId // error.duplicate_operation_id — повторный operationId } catch (InvalidConfigException $e) { // Возможные ключи: // error.invalid_column_name — небезопасное имя колонки // error.operation_id_attribute_not_found — нет колонки operationId // error.table_not_found — таблица не найдена // error.table_pk_required — нет PK у таблицы } ``` -------------------------------- ### Perform balance operations Source: https://github.com/nazbav/yii2-account-balance/blob/master/README.md Execute increase, decrease, and revert operations using the configured balance manager. ```php $manager = Yii::$app->balanceManager; $incomeTxId = $manager->increase( ['userId' => 101, 'walletType' => 'bonus_available'], 300, [ 'operationId' => 'order:5001:bonus', 'operationType' => 'purchase_bonus', 'orderId' => 5001, ] ); $expenseTxId = $manager->decrease( ['userId' => 101, 'walletType' => 'bonus_available'], 120, [ 'operationId' => 'order:5001:redeem', 'operationType' => 'order_redeem', ] ); $manager->revert($expenseTxId, [ 'operationType' => 'manual_fix', 'reason' => 'Корректировка по тикету поддержки', ]); ``` -------------------------------- ### Create Pending Referral Rewards Source: https://github.com/nazbav/yii2-account-balance/wiki/howto-referral-program Initialize pending rewards for both the referrer and the referred user using unique operation IDs. ```php $operationId = sprintf('ref:%d:%d:%s', $referrerUserId, $referredUserId, $programId); $manager->increase( ['userId' => $referrerUserId, 'walletType' => 'referral_pending'], $referrerReward, [ 'operationId' => $operationId, 'operationType' => 'referral_reward_pending', 'programId' => $programId, 'referrerUserId' => $referrerUserId, 'referredUserId' => $referredUserId, ] ); $manager->increase( ['userId' => $referredUserId, 'walletType' => 'referral_pending'], $referredReward, [ 'operationId' => $operationId . ':welcome', 'operationType' => 'referral_welcome_pending', 'programId' => $programId, 'referrerUserId' => $referrerUserId, 'referredUserId' => $referredUserId, ] ); ``` -------------------------------- ### Static Analysis with PHPStan Source: https://github.com/nazbav/yii2-account-balance/blob/master/docs/README.md Perform static analysis using PHPStan to catch errors and improve code quality. This command runs the analysis with a specific configuration. ```bash phpstan analyse -c phpstan.neon --no-progress ``` -------------------------------- ### Configure Manager Security Flags Source: https://github.com/nazbav/yii2-account-balance/wiki/howto-loyalty-levels Essential configuration settings for the account balance manager to ensure data integrity and prevent duplicate operations. ```php 'forbidDuplicateOperationId' => true, 'requireOperationId' => true, 'operationIdAttribute' => 'operationId', 'forbidNegativeBalance' => true, 'accountBalanceAttribute' => 'balance', ``` -------------------------------- ### Configure BalanceRules Source: https://github.com/nazbav/yii2-account-balance/wiki/reference-configuration Sets strict constraints on balance operations such as minimum balance and negative balance prevention. ```php use nazbavalancealanceRules; $manager->setBalanceRules(new BalanceRules( requirePositiveAmount: true, forbidTransferToSameAccount: true, forbidNegativeBalance: true, minimumAllowedBalance: 0, )); ``` -------------------------------- ### Perform balance operations Source: https://github.com/nazbav/yii2-account-balance/wiki/tutorial-quick-start Execute increase, transfer, and revert operations using the balance manager. ```php $manager = Yii::$app->balanceManager; $incomeId = $manager->increase( ['userId' => 1001, 'walletType' => 'bonus_available'], 500, [ 'operationId' => 'purchase:100500:bonus', 'operationType' => 'purchase_bonus', 'orderId' => 100500, ] ); $transferIds = $manager->transfer( ['userId' => 1001, 'walletType' => 'bonus_available'], ['userId' => 1001, 'walletType' => 'bonus_spent'], 120, [ 'operationId' => 'redeem:100500', 'operationType' => 'redeem', ] ); $manager->revert($transferIds[0], [ 'operationType' => 'manual_correction', 'reason' => 'Отмена списания оператором', ]); ``` -------------------------------- ### Idempotency and Anti-Replay Protection Source: https://github.com/nazbav/yii2-account-balance/wiki/examples-advanced-scenarios Demonstrates how to prevent duplicate operations by using unique `operationId` values. The second identical call will fail if `forbidDuplicateOperationId` is enabled. ```php $manager->increase( ['userId' => $userId, 'walletType' => 'bonus_available'], 50, [ 'operationId' => "campaign:$campaignId:user:$userId", 'operationType' => 'campaign_bonus', ] ); // Повтор того же события с тем же operationId: $manager->increase( ['userId' => $userId, 'walletType' => 'bonus_available'], 50, [ 'operationId' => "campaign:$campaignId:user:$userId", 'operationType' => 'campaign_bonus', ] ); ``` -------------------------------- ### Accrue Order Bonuses Source: https://github.com/nazbav/yii2-account-balance/wiki/howto-loyalty-levels Calculates and applies bonuses based on user tier and updates qualifying points for future tier progression. ```php $multiplier = match ($tier) { 'platinum' => 2.0, 'gold' => 1.5, 'silver' => 1.2, default => 1.0, }; $baseBonus = round($orderAmount * 0.05, 2); $finalBonus = round($baseBonus * $multiplier, 2); $manager->increase( ['userId' => $userId, 'walletType' => 'bonus_pending'], $finalBonus, [ 'operationId' => "order:$orderId:bonus_pending", 'operationType' => 'purchase_bonus_pending', 'tierAtPurchase' => $tier, 'multiplier' => $multiplier, ] ); $manager->increase( ['userId' => $userId, 'walletType' => 'qualifying_points'], (int) floor($orderAmount), [ 'operationId' => "order:$orderId:qualifying", 'operationType' => 'qualifying_points_accrual', ] ); ``` -------------------------------- ### Mermaid Flowchart for Documentation Navigation Source: https://github.com/nazbav/yii2-account-balance/wiki/Home This Mermaid flowchart visualizes the navigation structure of the documentation, showing the relationships between different sections and their corresponding files. ```mermaid flowchart TD A[Старт] --> B[tutorial-quick-start.md] B --> C[reference-configuration.md] C --> L[reference-behavior-matrix.md] C --> D{Прикладная задача} D --> E[Лояльность] D --> F[Реферальная программа] D --> G[Сложные сценарии] D --> H[Антифрод и безопасность] E --> E1[howto-loyalty-levels.md] F --> F1[howto-referral-program.md] G --> G1[examples-advanced-scenarios.md] H --> H1[explanation-fraud-controls.md] C --> K[faq-and-troubleshooting.md] ``` -------------------------------- ### Revert Logic Source: https://github.com/nazbav/yii2-account-balance/wiki/reference-behavior-matrix Explains the specific actions taken by the `revert()` method based on the type of the original transaction. ```APIDOC ## Revert Logic This section describes the actual behavior of the `revert()` method based on the characteristics of the original transaction. ### Revert Action Based on Original Transaction | Original Transaction | What `revert()` Does | |---|---| | Regular transaction with a positive amount | Calls `decrease()` on the same account. | | Regular transaction with a negative amount | Calls `increase()` on the same account. | | Transfer transaction with `extraAccountLinkAttribute` and a negative amount | Performs a reverse `transfer(extra -> account)`. | | Transfer transaction with `extraAccountLinkAttribute` and a positive amount | Performs a reverse `transfer(account -> extra)`. | ``` -------------------------------- ### ManagerInterface Methods Source: https://github.com/nazbav/yii2-account-balance/wiki/reference-configuration The core interface defining operations for account balance management, including increasing, decreasing, transferring, reverting, and calculating balances. ```APIDOC ## ManagerInterface Methods ### Description Defines the contract for account balance operations. ### Methods - **increase(mixed $account, int|float $amount, array $data = [])** - Increases the balance of an account. - **decrease(mixed $account, int|float $amount, array $data = [])** - Decreases the balance of an account. - **transfer(mixed $from, mixed $to, int|float $amount, array $data = [])** - Transfers funds between two accounts. - **revert(mixed $transactionId, array $data = [])** - Reverts a specific transaction. - **calculateBalance(mixed $account)** - Returns the current balance of an account. ``` -------------------------------- ### Hold and Capture Bonus Funds Source: https://github.com/nazbav/yii2-account-balance/wiki/examples-advanced-scenarios Places a bonus amount on hold and then captures it for spending. This is a two-step process for managing funds that are committed but not yet spent. ```php $holdTxId = $manager->transfer( ['userId' => $userId, 'walletType' => 'bonus_available'], ['userId' => $userId, 'walletType' => 'bonus_hold'], $holdAmount, [ 'operationId' => "checkout:$checkoutId:hold", 'operationType' => 'bonus_hold_create', ] ); $manager->transfer( ['userId' => $userId, 'walletType' => 'bonus_hold'], ['userId' => $userId, 'walletType' => 'bonus_spent'], $holdAmount, [ 'operationId' => "checkout:$checkoutId:capture", 'operationType' => 'bonus_hold_capture', 'sourceTransfer' => $holdTxId, ] ); ``` -------------------------------- ### Mutation Testing with Infection Source: https://github.com/nazbav/yii2-account-balance/blob/master/docs/README.md Conduct mutation testing on core manager classes using Infection. This helps ensure the test suite is effective at detecting code changes. ```bash infection --threads=max --only-covered --filter=src/Manager.php,src/ManagerDb.php,src/ManagerActiveRecord.php --no-progress ``` -------------------------------- ### Purchase with Delayed Bonus Credit and Release Source: https://github.com/nazbav/yii2-account-balance/wiki/examples-advanced-scenarios Initiates a pending bonus credit for a purchase and then transfers it to the available balance. Use for scenarios where bonuses are awarded after a certain period or condition. ```php $pendingTxId = $manager->increase( ['userId' => $userId, 'walletType' => 'bonus_pending'], $bonusAmount, [ 'operationId' => "order:$orderId:bonus_pending", 'operationType' => 'purchase_bonus_pending', 'riskWindowDays' => 14, ] ); $manager->transfer( ['userId' => $userId, 'walletType' => 'bonus_pending'], ['userId' => $userId, 'walletType' => 'bonus_available'], $bonusAmount, [ 'operationId' => "order:$orderId:bonus_release", 'operationType' => 'purchase_bonus_release', 'sourceTransactionId' => $pendingTxId, ] ); ``` -------------------------------- ### Taint Analysis with Psalm Source: https://github.com/nazbav/yii2-account-balance/blob/master/docs/README.md Run taint analysis with Psalm to identify potential security vulnerabilities related to data flow. This command checks for taint streams. ```bash psalm --taint-analysis --no-cache --output-format=console ``` -------------------------------- ### Operation Behavior Matrix Source: https://github.com/nazbav/yii2-account-balance/wiki/reference-configuration Details the behavior of different operations under various conditions, including amount validation, fund availability, and account existence. ```APIDOC ## Operation Behavior Matrix | Operation | | Amount <= 0 | | Insufficient Funds | | Account not found by filter | | Result | | Separate DB Transaction | | `increase` | error (if `requirePositiveAmount=true`) | not applicable | auto-creation / error | transaction with `+amount` | yes | | `decrease` | error (if `requirePositiveAmount=true`) | error (if `forbidNegativeBalance=true`) | auto-creation / error | transaction with `-amount` | yes | | `transfer` | error (if `requirePositiveAmount=true`) | error on source account | auto-creation / error | two transactions | yes | | `revert` | not applicable | depends on original operation | not applicable | reverse operation | yes | Detailed actual logic: [Actual behavior matrix](reference-behavior-matrix.md). ``` -------------------------------- ### Handle Transaction Events in PHP Source: https://context7.com/nazbav/yii2-account-balance/llms.txt Utilize `EVENT_BEFORE_CREATE_TRANSACTION` and `EVENT_AFTER_CREATE_TRANSACTION` to add data or perform side effects. The `TransactionEvent` object provides access to transaction details and allows modification before creation or logging after completion. ```php use nazbav\balance\Manager; use nazbav\balance\TransactionEvent; // Добавление trace ID для distributed tracing $manager->on(Manager::EVENT_BEFORE_CREATE_TRANSACTION, static function (TransactionEvent $event): void { $event->transactionData['traceId'] = Yii::$app->request->headers->get('X-Trace-Id'); }); // Логирование после создания транзакции $manager->on(Manager::EVENT_AFTER_CREATE_TRANSACTION, static function (TransactionEvent $event): void { Yii::info([ 'transactionId' => $event->transactionId, 'accountId' => $event->accountId, 'amount' => $event->transactionData['amount'], ], 'balance'); }); ``` -------------------------------- ### Multi-stage Referral Reward Source: https://github.com/nazbav/yii2-account-balance/wiki/examples-advanced-scenarios Awards a referral bonus in two stages: first a pending credit, then a transfer to the available balance. This allows for phased reward distribution. ```php $manager->increase( ['userId' => $referrerUserId, 'walletType' => 'referral_pending'], 300, [ 'operationId' => "ref:$programId:$referrerUserId:$referredUserId:pending", 'operationType' => 'referral_pending', ] ); $manager->transfer( ['userId' => $referrerUserId, 'walletType' => 'referral_pending'], ['userId' => $referrerUserId, 'walletType' => 'bonus_available'], 300, [ 'operationId' => "ref:$programId:$referrerUserId:$referredUserId:release", 'operationType' => 'referral_release', ] ); ``` -------------------------------- ### Loyalty Cycle Diagram Source: https://github.com/nazbav/yii2-account-balance/wiki/howto-loyalty-levels Visual representation of the loyalty lifecycle from purchase to bonus redemption. ```mermaid flowchart LR A[Покупка] --> B[Начисление в bonus_pending] A --> C[Начисление qualifying_points] C --> D[Пересчет уровня] B --> E{Окно риска} E -- Пройдено --> F[Перевод в bonus_available] E -- Фрод/Возврат --> G[Откат/revert] F --> H[Списание в бонусный платеж] ``` -------------------------------- ### Manager Configuration Properties Source: https://github.com/nazbav/yii2-account-balance/blob/master/docs/reference-configuration.md Configuration properties for the Manager class to control balance behavior and validation. ```APIDOC ## Manager Configuration Properties ### Description Key properties used to configure the behavior of the balance manager, including validation rules and attribute mapping. ### Properties - **autoCreateAccount** (bool) - Default: true - Automatically create account if not found. - **requirePositiveAmount** (bool) - Default: true - Require amount > 0 for public operations. - **forbidNegativeBalance** (bool) - Default: false - Block balance from dropping below minimum. - **minimumAllowedBalance** (int|float) - Default: 0 - The lower boundary for account balance. - **forbidDuplicateOperationId** (bool) - Default: false - Prevent duplicate operation IDs for the same account. ``` -------------------------------- ### Error Codes and Exceptions Source: https://github.com/nazbav/yii2-account-balance/wiki/reference-configuration A comprehensive list of error codes, their corresponding exception types, and the conditions under which they are raised. ```APIDOC ## Error Codes and Exceptions | Message Key | | Type of Exception | | When it occurs | | `error.amount_not_numeric` | `InvalidArgumentException` | The amount is not a number. | | `error.amount_must_be_positive` | `InvalidArgumentException` | The amount is `<= 0` when strictly required. | | `error.amount_must_be_finite` | `InvalidArgumentException` | `INF/-INF/NAN` were provided. | | `error.transfer_same_account_forbidden` | `InvalidArgumentException` | Transfer to the same account is forbidden. | | `error.transaction_not_found` | `InvalidArgumentException` | Transaction not found for `revert()`. | | `error.insufficient_funds` | `InvalidArgumentException` | Insufficient funds in protection mode. | | `error.invalid_column_name` | `InvalidConfigException` | Unsafe column name. | | `error.operation_id_required` | `InvalidArgumentException` | Required `operationId` was not provided. | | `error.operation_id_invalid` | `InvalidArgumentException` | Empty or non-string `operationId` was provided. | | `error.duplicate_operation_id` | `InvalidArgumentException` | Duplicate `operationId` for the same account. | | `error.operation_id_attribute_not_found` | `InvalidConfigException` | The transaction table does not have a column for `operationId`. | | `error.account_attributes_empty_after_filter` | `InvalidArgumentException` | Filter provided for auto-account creation has no valid schema attributes. | | `error.table_not_found` | `InvalidConfigException` | Table not found. | | `error.table_pk_required` | `InvalidConfigException` | Table has no Primary Key. | | `error.property_must_be_active_record_class` | `InvalidConfigException` | Invalid AR class. | ``` -------------------------------- ### Manager Configuration Source: https://github.com/nazbav/yii2-account-balance/wiki/reference-configuration Configuration properties for the Manager component, including balance rules and attribute mapping. ```APIDOC ## Manager Configuration ### Description Properties used to configure the behavior of the balance manager, such as strict mode, balance limits, and attribute names. ### Key Properties - **autoCreateAccount** (bool) - Default: true - Automatically create account if not found. - **forbidNegativeBalance** (bool) - Default: false - Block balance from going below minimum. - **minimumAllowedBalance** (int|float) - Default: 0 - The lower boundary for account balance. - **requireOperationId** (bool) - Default: false - Require operationId in transaction data. ### Example ```php $manager->setBalanceRules(new BalanceRules( requirePositiveAmount: true, forbidTransferToSameAccount: true, forbidNegativeBalance: true, minimumAllowedBalance: 0, )); ``` ``` -------------------------------- ### Handle Transaction Events Source: https://github.com/nazbav/yii2-account-balance/blob/master/docs/reference-configuration.md Attach custom logic to manager events, such as injecting trace IDs into transaction data before creation. ```php use nazbavalance\Manager; use nazbavalance\TransactionEvent; $manager->on(Manager::EVENT_BEFORE_CREATE_TRANSACTION, static function (TransactionEvent $event): void { $event->transactionData['traceId'] = Yii::$app->request->headers->get('X-Trace-Id'); }); ``` -------------------------------- ### Recalculate User Tier Source: https://github.com/nazbav/yii2-account-balance/wiki/howto-loyalty-levels Determines the user's current loyalty tier based on their total qualifying points balance. ```php $qualifyingBalance = $manager->calculateBalance([ 'userId' => $userId, 'walletType' => 'qualifying_points', ]); $newTier = match (true) { $qualifyingBalance >= 15000 => 'platinum', $qualifyingBalance >= 5000 => 'gold', $qualifyingBalance >= 1000 => 'silver', default => 'bronze', }; ``` -------------------------------- ### Test Coverage Source: https://github.com/nazbav/yii2-account-balance/wiki/reference-behavior-matrix Provides statistics on the test suite, including the number of tests, assertions, failures, and distribution across test files. ```APIDOC ## Test Coverage This section provides factual information about the test coverage for the account balance module. ### Test Execution Statistics - Executed tests in `phpunit`: `124`. - Actual results from the last run: - `124 tests`; - `236 assertions`; - `0 failures`. ### Test Distribution - `tests/ManagerTest.php`: `41` tests. - `tests/ManagerDbTest.php`: `36` tests. - `tests/ManagerActiveRecordTest.php`: `37` tests. - `tests/ManagerDataSerializeTraitTest.php`: `10` tests (some via data provider). ### Test Scope Tests cover positive and negative scenarios for amount validation, same-account transfer prohibition, overdraft protection, data serialization, and events. ``` -------------------------------- ### decrease() - Decrease Account Balance Source: https://context7.com/nazbav/yii2-account-balance/llms.txt Reduces the account balance (credit operation). Optionally blocks the operation if the balance falls below the minimum. ```APIDOC ## decrease(account, amount, metadata) ### Description Decreases the balance of a specified account. If forbidNegativeBalance is enabled, it prevents the operation if the balance would drop below the minimum. ### Parameters - **account** (array) - Required - Account identifier (e.g., ['userId' => 1001, 'walletType' => 'bonus_available']) - **amount** (float/int) - Required - The amount to decrease - **metadata** (array) - Optional - Additional data including operationId and operationType ### Response - **transactionId** (int) - The ID of the created transaction ``` -------------------------------- ### Configure ManagerDb Component for Yii2 Source: https://context7.com/nazbav/yii2-account-balance/llms.txt Configure the `ManagerDb` component for direct SQL operations. Specify database connection, table names, and various operational parameters for strict production environments. ```php use nazbav\balance\ManagerDb; return [ 'components' => [ 'balanceManager' => [ 'class' => ManagerDb::class, 'db' => 'db', 'accountTable' => '{{%balance_account}}', 'transactionTable' => '{{%balance_balance_transaction}}', 'accountLinkAttribute' => 'accountId', 'extraAccountLinkAttribute' => 'extraAccountId', 'accountBalanceAttribute' => 'balance', 'amountAttribute' => 'amount', 'dateAttribute' => 'createdAt', 'dataAttribute' => 'data', 'autoCreateAccount' => true, // Строгий профиль для продакшна 'requirePositiveAmount' => true, 'forbidTransferToSameAccount' => true, 'forbidNegativeBalance' => true, 'forbidDuplicateOperationId' => true, 'requireOperationId' => true, 'operationIdAttribute' => 'operationId', 'minimumAllowedBalance' => 0, ], ], ]; ``` -------------------------------- ### Overdraft Protection Source: https://github.com/nazbav/yii2-account-balance/wiki/reference-behavior-matrix Explains the mechanisms and conditions for preventing negative account balances. ```APIDOC ## Overdraft Protection This section describes the overdraft protection features and their behavior. ### Protection Settings and Behavior | Parameter | Behavior | |---|---| | `forbidNegativeBalance=false` | The balance is allowed to go below zero. | | `forbidNegativeBalance=true` + `accountBalanceAttribute!==null` | Conditional atomic update is performed; if unsuccessful, `error.insufficient_funds` is thrown. | | `forbidNegativeBalance=true` + `accountBalanceAttribute===null` | Configuration error `error.account_balance_attribute_required_for_negative_protection` is thrown. | ``` -------------------------------- ### Data Serialization Source: https://github.com/nazbav/yii2-account-balance/wiki/reference-behavior-matrix Details how additional data associated with transactions is serialized. ```APIDOC ## Data Serialization This section explains the serialization process for the `data` field in transactions. ### Serialization Behavior | Condition | Behavior | |---|---| | `dataAttribute=null` | Additional fields are not serialized. | | `dataAttribute` is set | Attributes not known to the fields are packed by the serializer. | | `serializer='json'` | `JsonSerializer` is used. | | `serializer='php'` | `PhpSerializer` is used. | | `PhpSerializer` default | `allowedClasses=false`, object creation in `unserialize()` is forbidden. | ```