├── composer.json ├── database └── migrations │ └── 2017_06_24_092243_create_ledger_entries_table.php ├── readme.md ├── resources └── assets │ └── js │ └── components │ └── ledger │ └── Ledger.vue └── src ├── EntryRepository.php ├── Exceptions ├── InsufficientBalanceException.php └── InvalidRecipientException.php ├── Facades └── Ledger.php ├── Http └── Controllers │ ├── Controller.php │ └── LedgerController.php ├── Ledger.php ├── LedgerEntry.php ├── LedgerServiceProvider.php └── Traits └── Ledgerable.php /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fannypack/ledger", 3 | "description": "ledger implementation for laravel", 4 | "keywords": ["library", "laravel", "php", "ledger"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Mpande Andrew", 9 | "email": "andrewmvp007@gmail.com" 10 | } 11 | ], 12 | "minimum-stability": "dev", 13 | "autoload": { 14 | "psr-4": { 15 | "FannyPack\\Ledger\\": "src/" 16 | } 17 | }, 18 | "extra": { 19 | "laravel": { 20 | "providers": [ 21 | "FannyPack\\Ledger\\LedgerServiceProvider" 22 | ], 23 | "aliases": { 24 | "Ledger": "FannyPack\\Ledger\\Facades\\Ledger" 25 | } 26 | } 27 | }, 28 | "require": { 29 | "illuminate/database": "~5.4.0|~5.5.0|~5.6.0|~5.7.0|~5.8.0", 30 | "illuminate/support": "~5.4.0|~5.5.0|~5.6.0|~5.7.0|~5.8.0", 31 | "illuminate/routing": "~5.4.0|~5.5.0|~5.6.0|~5.7.0|~5.8.0", 32 | "illuminate/validation": "~5.4.0|~5.5.0|~5.6.0|~5.7.0|~5.8.0", 33 | "nesbot/carbon": "^1.26.3 || ^2.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /database/migrations/2017_06_24_092243_create_ledger_entries_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 16 | $table->morphs('ledgerable'); 17 | $table->string('money_to')->nullable(); 18 | $table->string('money_from')->nullable(); 19 | $table->text('reason'); 20 | $table->boolean('credit')->default(0); 21 | $table->boolean('debit')->default(0); 22 | $table->float('amount', 8, 2); 23 | $table->string('amount_currency')->nullable(); 24 | $table->float('current_balance', 8, 2); 25 | $table->string('current_balance_currency')->nullable(); 26 | $table->timestamps(); 27 | }); 28 | } 29 | /** 30 | * Reverse the migrations. 31 | * 32 | * @return void 33 | */ 34 | public function down() 35 | { 36 | Schema::dropIfExists('ledger_entries'); 37 | } 38 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## About this library 2 | 3 | This is a simple/basic implementation of a ledger in laravel 5 4 | 5 | ## Actions supported 6 | - RECORDING DEBITS 7 | - RECORDING CREDITS 8 | - BALANCE COMPUTATION 9 | 10 | ## Installation 11 | git clone https://github.com/mpaannddreew/laravel-ledger.git 12 | 13 | Register service provider 14 | ```php 15 | FannyPack\Ledger\LedgerServiceProvider::class, 16 | ``` 17 | Register Facade 18 | Register service provider 19 | ```php 20 | 'Ledger' => FannyPack\Ledger\Facades\Ledger::class, 21 | ``` 22 | 23 | After the service provider is registered run this command 24 | ``` 25 | php artisan vendor:publish --tag=ledger 26 | ``` 27 | Run migrations 28 | ``` 29 | php artisan migrate 30 | ``` 31 | This command will copy the library's vue components into your codebase 32 | 33 | Register package routes in your app's RouteServiceProvider 34 | ``` 35 | Ledger::routes(); 36 | ``` 37 | 38 | ## Usage 39 | Using it with your models, add 40 | ```php 41 | namespace App; 42 | 43 | use FannyPack\Ledger\Traits\Ledgerable; 44 | use Illuminate\Database\Eloquent\Model; 45 | 46 | class Account extends Model 47 | { 48 | use Ledgerable; 49 | } 50 | ``` 51 | 52 | Show available balance 53 | ```php 54 | $account = Account::find(1); 55 | $balance = Ledger::balance($account); 56 | ``` 57 | or 58 | ```php 59 | $account = Account::find(1); 60 | $balance = $account->balance(); 61 | ``` 62 | Record a credit entry 63 | ```php 64 | $account = Account::find(1); 65 | Ledger::credit($account, $to, $amount, $reason); 66 | ``` 67 | or 68 | ```php 69 | $account = Account::find(1); 70 | $account->credit($to, $amount, $reason); 71 | ``` 72 | Record a debit entry 73 | ```php 74 | $account = Account::find(1); 75 | Ledger::debit($account, $from, $amount, $reason); 76 | ``` 77 | or 78 | ```php 79 | $account = Account::find(1); 80 | $account->debit($from, $amount, $reason); 81 | ``` 82 | 83 | Recording debits and credits in one transaction 84 | ```php 85 | $account = Account::find(1); 86 | $account2 = Account::find(2); 87 | $account3 = Account::find(3); 88 | Ledger::transfer($account, [$account2, $account3], $amount, $reason); 89 | // or 90 | Ledger::transfer($account, $account2, $amount, $reason); 91 | Ledger::transfer($account, $account3, $amount, $reason); 92 | ``` 93 | or 94 | ```php 95 | $account = Account::find(1); 96 | $account2 = Account::find(2); 97 | $account3 = Account::find(3); 98 | $account->transfer([$account2, $account3], $amount, $reason); 99 | // or 100 | $account->transfer($account2, $amount, $reason); 101 | $account->transfer($account3, $amount, $reason); 102 | ``` 103 | Retrieving all entries of a ledgerable 104 | ```php 105 | $account = Account::find(1); 106 | $entries = $account->entries(); 107 | ``` 108 | Retrieving all debits of a ledgerable 109 | ```php 110 | $account = Account::find(1); 111 | debits = $account->debits(); 112 | ``` 113 | Retrieving all credits of a ledgerable 114 | ```php 115 | $account = Account::find(1); 116 | debits = $account->credits(); 117 | ``` 118 | Using the provided Ledger.vue component in your blade templates 119 | ```php 120 | 121 | ``` 122 | 123 | ## Bugs 124 | For any bugs found, please email me at andrewmvp007@gmail.com or register an issue at [issues](https://github.com/mpaannddreew/laravel-ledger/issues) 125 | -------------------------------------------------------------------------------- /resources/assets/js/components/ledger/Ledger.vue: -------------------------------------------------------------------------------- 1 | 87 | 90 | 255 | -------------------------------------------------------------------------------- /src/EntryRepository.php: -------------------------------------------------------------------------------- 1 | 'credit', 'debit' => 'debit']; 32 | 33 | /** 34 | * EntryRepository constructor. 35 | * @param Carbon $carbon 36 | */ 37 | public function __construct(Carbon $carbon) 38 | { 39 | $this->time = $carbon->setTimezone($carbon->getTimezone()); 40 | } 41 | 42 | /** 43 | * get ledger entries 44 | * 45 | * @param int $days_ago 46 | * @param int $offset 47 | * @param int $limit 48 | * @return array 49 | */ 50 | public function getEntries($days_ago = 0, $offset = 0, $limit = 10) 51 | { 52 | if($days_ago) 53 | return $this->fromDaysAgo(null, $days_ago, $offset, $limit); 54 | 55 | $response = []; 56 | $entries = LedgerEntry::select()->latest()->skip($offset)->take($limit)->orderBy('id', 'desc')->get();; 57 | foreach ($entries as $entry) 58 | { 59 | $item = $entry->toArray(); 60 | $item['name'] = $entry->ledgerable->name; 61 | array_push($response, $item); 62 | } 63 | 64 | return $response; 65 | } 66 | 67 | /** 68 | * get ledger entries according to type 69 | * 70 | * @param $type 71 | * @param int $days_ago 72 | * @param int $offset 73 | * @param int $limit 74 | * @return array 75 | */ 76 | public function getTypeEntries($type, $days_ago = 0, $offset = 0, $limit = 10) 77 | { 78 | if($days_ago) 79 | return $this->fromDaysAgo($type, $days_ago, $offset, $limit); 80 | 81 | if (!array_has($this->entry_type, strtolower($type))) 82 | return []; 83 | 84 | $response = []; 85 | $entries = LedgerEntry::select()->where(strtolower($type), '=', 1)->latest()->skip($offset)->take($limit)->orderBy('id', 'desc')->get(); 86 | foreach ($entries as $entry) 87 | { 88 | $item = $entry->toArray(); 89 | $item['name'] = $entry->ledgerable->name; 90 | array_push($response, $item); 91 | } 92 | return $response; 93 | } 94 | 95 | /** 96 | * find a specific ledger entry 97 | * 98 | * @param $entry_id 99 | * @return mixed 100 | */ 101 | public function find($entry_id) 102 | { 103 | $entry = LedgerEntry::find($entry_id); 104 | 105 | $item = $entry->toArray(); 106 | $item['name'] = $entry->ledgerable->name; 107 | 108 | return $item; 109 | } 110 | 111 | /** 112 | * get entries starting from specific date 113 | * 114 | * @param $date 115 | * @param int $days_from_date 116 | * @param null|string $type 117 | * @param int $offset 118 | * @param int $limit 119 | * @return array 120 | */ 121 | public function findFromDate($date, $days_from_date = 1, $type = null, $offset = 0, $limit = 100) 122 | { 123 | $response = []; 124 | list($year, $month, $day) = $this->getYearMonthDay($date); 125 | 126 | $datetime = $this->time->setDate($year, $month, $day)->setTimeFromTimeString("00:01:00"); 127 | 128 | if ($type){ 129 | if (!array_has($this->entry_type, strtolower($type))) 130 | return []; 131 | 132 | 133 | $entries = LedgerEntry::select()->where($type, '=', 1)->where('created_at', '>=', $datetime->toDateTimeString()) 134 | ->where('created_at', '<=', $datetime->addDay($days_from_date)->toDateTimeString()) 135 | ->latest()->skip($offset)->take($limit)->orderBy('id', 'desc')->get(); 136 | foreach ($entries as $entry) 137 | { 138 | $item = $entry->toArray(); 139 | $item['name'] = $entry->ledgerable->name; 140 | array_push($response, $item); 141 | } 142 | 143 | return $response; 144 | } 145 | 146 | $entries = LedgerEntry::select()->where('created_at', '>=', $datetime->toDateTimeString()) 147 | ->where('created_at', '<=', $datetime->addDay($days_from_date)->toDateTimeString()) 148 | ->latest()->skip($offset)->take($limit)->orderBy('id', 'desc')->get(); 149 | foreach ($entries as $entry) 150 | { 151 | $item = $entry->toArray(); 152 | $item['name'] = $entry->ledgerable->name; 153 | array_push($response, $item); 154 | } 155 | 156 | return $response; 157 | } 158 | 159 | /** 160 | * get entries from a number of days ago 161 | * 162 | * @param null|string $type 163 | * @param int $days_ago 164 | * @param int $offset 165 | * @param int $limit 166 | * @return array 167 | */ 168 | protected function fromDaysAgo($type = null, $days_ago = 0, $offset = 0, $limit = 10) 169 | { 170 | $response = []; 171 | $datetime = $this->dateFromThen($days_ago); 172 | 173 | if ($type){ 174 | if (!array_has($this->entry_type, strtolower($type))) 175 | return []; 176 | 177 | $entries = LedgerEntry::select()->where($type, '=', 1)->where('created_at', '>=', $datetime->toDateTimeString())->latest()->skip($offset)->take($limit)->orderBy('id', 'desc')->get(); 178 | foreach ($entries as $entry) 179 | { 180 | $item = $entry->toArray(); 181 | $item['name'] = $entry->ledgerable->name; 182 | array_push($response, $item); 183 | } 184 | 185 | return $response; 186 | } 187 | 188 | $entries = LedgerEntry::select()->where('created_at', '>=', $datetime->toDateTimeString())->latest()->skip($offset)->take($limit)->orderBy('id', 'desc')->get(); 189 | foreach ($entries as $entry) 190 | { 191 | $item = $entry->toArray(); 192 | $item['name'] = $entry->ledgerable->name; 193 | array_push($response, $item); 194 | } 195 | 196 | return $response; 197 | } 198 | 199 | /** 200 | * get datetime from string 201 | * 202 | * @param string $datetime 203 | * @return static 204 | */ 205 | protected function fromDateTimeString($datetime) 206 | { 207 | $datetime = explode(' ', $datetime); 208 | $date = $datetime[0]; 209 | $time = $datetime[1]; 210 | 211 | list($year, $month, $day) = $this->getYearMonthDay($date); 212 | 213 | return $this->time->setDate($year, $month, $day)->setTimeFromTimeString($time); 214 | } 215 | 216 | /** 217 | * get date days ago 218 | * 219 | * @param $days 220 | * @return static 221 | */ 222 | protected function dateFromThen($days) 223 | { 224 | return $this->time->now()->subDays($days); 225 | } 226 | 227 | /** 228 | * get year, month, day from date string 229 | * 230 | * @param $date 231 | * @return array 232 | */ 233 | protected function getYearMonthDay($date) 234 | { 235 | return explode('-', $date); 236 | } 237 | } -------------------------------------------------------------------------------- /src/Exceptions/InsufficientBalanceException.php: -------------------------------------------------------------------------------- 1 | middleware('auth:api')->except(['index']); 33 | $this->middleware(['web', 'auth'])->only(['index']); 34 | $this->ledger = $ledger; 35 | $this->validator = $validator; 36 | } 37 | 38 | /** 39 | * Display a listing of the resource. 40 | * 41 | * @param Request $request 42 | * @return \Illuminate\Http\Response 43 | * @throws \Illuminate\Validation\ValidationException 44 | */ 45 | public function index(Request $request) 46 | { 47 | $this->validator->make($request->all(), [ 48 | 'offset' => 'numeric', 49 | 'limit' => 'numeric', 50 | 'days_ago' => 'numeric', 51 | 'entry_type' => 'alpha', 52 | 'from_date' => 'date|date_format:Y-m-d', 53 | 'days_from_date' => 'numeric', 54 | ])->validate(); 55 | 56 | $offset = (int)$request->input('offset', 0); 57 | $limit = (int)$request->input('limit', 10); 58 | $days = (int)$request->input('days_ago', 0); 59 | $type = $request->input('entry_type', ''); 60 | $from_date = $request->input('from_date', ''); 61 | $days_from_date = $request->input('days_from_date', 1); 62 | 63 | if ($from_date) 64 | { 65 | $entries = $this->ledger->findFromDate($from_date, $days_from_date, $type, $offset, $limit); 66 | }else{ 67 | if ($type) 68 | { 69 | $entries = $this->ledger->getTypeEntries($type, $days, $offset, $limit); 70 | }else { 71 | $entries = $this->ledger->getEntries($days, $offset, $limit); 72 | } 73 | } 74 | 75 | $response = [ 76 | 'success' => true, 77 | 'count' => count($entries), 78 | 'offset' => $offset, 79 | 'limit' => $limit, 80 | 'data' => $entries 81 | ]; 82 | 83 | if ($days) $response['days_ago'] = $days; 84 | 85 | if ($type) $response['entry_type'] = $type; 86 | 87 | if ($from_date) { 88 | $response['from_date'] = $from_date; 89 | 90 | if ($days_from_date) $response['days_from_date'] = $days_from_date; 91 | } 92 | 93 | return response()->json($response); 94 | } 95 | 96 | /** 97 | * Display the specified resource. 98 | * 99 | * @param Request $request 100 | * @param $entry_id 101 | * @return \Illuminate\Http\Response 102 | * @throws \Illuminate\Validation\ValidationException 103 | */ 104 | public function show(Request $request, $entry_id) 105 | { 106 | $this->validator->make(['entry_id' => $entry_id], [ 107 | 'entry_id' => 'required|numeric', 108 | ])->validate(); 109 | 110 | $entry = $this->ledger->find((int)$entry_id); 111 | $response = [ 112 | 'success' => true, 113 | 'item' => $entry 114 | ]; 115 | 116 | return response()->json($response); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/Ledger.php: -------------------------------------------------------------------------------- 1 | router = $router; 30 | } 31 | 32 | /** 33 | * debit a ledgerable instance 34 | * 35 | * @param $to 36 | * @param string $from 37 | * @param $amount 38 | * @param $reason 39 | * @return mixed 40 | */ 41 | public function debit($to, $from, $amount, $amount_currency, $reason) 42 | { 43 | $balance = $to->balance(); 44 | $current_balance_currency = isset($to->current_balance_currency) ? $to->current_balance_currency : Null; 45 | 46 | $data = [ 47 | 'money_from' => $from, 48 | 'debit' => 1, 49 | 'reason' => $reason, 50 | 'amount' => $amount, 51 | 'amount_currency' => $amount_currency, 52 | 'current_balance' => (float)$balance + (float)$amount, 53 | 'current_balance_currency' => $current_balance_currency 54 | ]; 55 | 56 | return $this->log($to, $data); 57 | } 58 | 59 | /** 60 | * credit a ledgerable instance 61 | * 62 | * @param $from 63 | * @param string $to 64 | * @param $amount 65 | * @param $reason 66 | * @return mixed 67 | * @throws InsufficientBalanceException 68 | */ 69 | public function credit($from, $to, $amount, $amount_currency="UGX", $reason) 70 | { 71 | $balance = $from->balance(); 72 | $current_balance_currency = isset($from->current_balance_currency) ? $from->current_balance_currency : Null; 73 | 74 | if ((float)$balance == 0 || (float)$amount > (float)$balance ) 75 | throw new InsufficientBalanceException("Insufficient balance"); 76 | 77 | $data = [ 78 | 'money_to' => $to, 79 | 'credit' => 1, 80 | 'reason' => $reason, 81 | 'amount' => $amount, 82 | 'amount_currency' => $amount_currency, 83 | 'current_balance' => (float)$balance - (float)$amount, 84 | 'current_balance_currency' => $current_balance_currency 85 | ]; 86 | 87 | return $this->log($from, $data); 88 | } 89 | 90 | /** 91 | * persist an entry to the ledger 92 | * 93 | * @param $ledgerable 94 | * @param array $data 95 | * @return mixed 96 | */ 97 | protected function log($ledgerable, array $data) 98 | { 99 | return $ledgerable->entries()->create($data); 100 | } 101 | 102 | /** 103 | * balance of a ledgerable instance 104 | * 105 | * @param $ledgerable 106 | * @return float 107 | */ 108 | public function balance($ledgerable) 109 | { 110 | $credits = $ledgerable->credits()->sum('amount'); 111 | $debits = $ledgerable->debits()->sum('amount'); 112 | $balance = $debits - $credits; 113 | return $balance; 114 | } 115 | 116 | /** 117 | * transfer an amount to each ledgerable instance 118 | * 119 | * @param $from 120 | * @param $to 121 | * @param $amount 122 | * @param string $reason 123 | * @return mixed 124 | * @throws InvalidRecipientException 125 | * @throws InsufficientBalanceException 126 | */ 127 | public function transfer($from, $to, $amount, $amount_currency="UGX", $reason = "funds transfer") 128 | { 129 | if (!is_array($to)) 130 | return $this->transferOnce($from, $to, $amount, $reason); 131 | 132 | $total_amount = (float)$amount * count($to); 133 | if ($total_amount > $from->balance()) 134 | throw new InsufficientBalanceException("Insufficient balance"); 135 | 136 | $recipients = []; 137 | foreach ($to as $recipient) 138 | { 139 | array_push($recipients, $this->transferOnce($from, $recipient, $amount, $amount_currency, $reason)); 140 | } 141 | 142 | return $recipients; 143 | } 144 | 145 | /** 146 | * transfer an amount to one ledgerable instance 147 | * 148 | * @param $from 149 | * @param $to 150 | * @param $amount 151 | * @param $reason 152 | * @return mixed 153 | * @throws InsufficientBalanceException 154 | * @throws InvalidRecipientException 155 | */ 156 | protected function transferOnce($from, $to, $amount, $amount_currency="UGX", $reason) 157 | { 158 | if (get_class($from) == get_class($to) && $from->id == $to->id) 159 | throw new InvalidRecipientException("Source and recipient cannot be the same object"); 160 | 161 | $this->credit($from, $to->name, $amount, $amount_currency ,$reason); 162 | return $this->debit($to, $from->name, $amount, $amount_currency, $reason); 163 | } 164 | 165 | /** 166 | * register routes for ledger api access 167 | */ 168 | public function routes() 169 | { 170 | $this->router->group(['namespace' => 'FannyPack\Ledger\Http\Controllers', 'prefix' => 'entries'], function() { 171 | $this->router->get('ledger', 'LedgerController@index'); 172 | $this->router->get('ledger/{entry_id}', 'LedgerController@show'); 173 | }); 174 | } 175 | } -------------------------------------------------------------------------------- /src/LedgerEntry.php: -------------------------------------------------------------------------------- 1 | 'boolean', 17 | 'debit' => 'boolean', 18 | 'created_at' => 'datetime' 19 | ]; 20 | 21 | 22 | /** 23 | * The table associated with the model. 24 | * 25 | * @var string 26 | */ 27 | protected $table = "ledger_entries"; 28 | 29 | /** 30 | * @var array 31 | */ 32 | protected $fillable = ['reason', 'debit', 'credit', 'amount_currency', 'amount', 'current_balance_currency', 'current_balance', 'money_to', 'money_from']; 33 | 34 | protected $hidden = ['ledgerable_id', 'ledgerable_type', 'current_balance', 'updated_at']; 35 | 36 | /** 37 | * Get the ledgerable entity that the entry belongs to. 38 | * 39 | * @return \Illuminate\Database\Eloquent\Relations\MorphTo 40 | */ 41 | public function ledgerable() 42 | { 43 | return $this->morphTo(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/LedgerServiceProvider.php: -------------------------------------------------------------------------------- 1 | loadMigrationsFrom(__DIR__.'/../database/migrations'); 18 | 19 | if ($this->app->runningInConsole()) { 20 | $this->publishes([ 21 | __DIR__.'/../resources/assets/js' => base_path('resources/assets/js'), 22 | ], 'ledger'); 23 | } 24 | } 25 | 26 | /** 27 | * Register the application services. 28 | * 29 | * @return void 30 | */ 31 | public function register() 32 | { 33 | $this->app->singleton(Ledger::class, function($app){ 34 | return new Ledger($app['router']); 35 | }); 36 | 37 | $this->app->when(EntryRepository::class) 38 | ->needs(Carbon::class) 39 | ->give(function(){ 40 | return new Carbon($tz="EAT"); 41 | }); 42 | } 43 | 44 | /** 45 | * services this provider provides 46 | * 47 | * @return array 48 | */ 49 | public function provides() 50 | { 51 | return [Ledger::class]; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Traits/Ledgerable.php: -------------------------------------------------------------------------------- 1 | morphMany(LedgerEntry::class, 'ledgerable')->orderBy('id', 'desc'); 25 | } 26 | 27 | /** 28 | * Get all of the entity's ledger debit entries. 29 | * 30 | * @return mixed 31 | */ 32 | public function debits() 33 | { 34 | return $this->entries()->where('debit', '=', 1); 35 | } 36 | 37 | /** 38 | * Get all of the entity's ledger credit entries. 39 | * 40 | * @return mixed 41 | */ 42 | public function credits() 43 | { 44 | return $this->entries()->where('credit', '=', 1); 45 | } 46 | 47 | /** 48 | * debit entity 49 | * 50 | * @param $from 51 | * @param $amount 52 | * @param $reason 53 | * @return mixed 54 | */ 55 | public function debit($from, $amount, $amount_currency="UGX", $reason) 56 | { 57 | return Ledger::debit($this, $from, $amount, $amount_currency, $reason); 58 | } 59 | 60 | /** 61 | * credit entity 62 | * 63 | * @param $to 64 | * @param $amount 65 | * @param $reason 66 | * @return mixed 67 | */ 68 | public function credit($to, $amount, $amount_currency="UGX", $reason) 69 | { 70 | return Ledger::credit($this, $to, $amount, $amount_currency, $reason); 71 | } 72 | 73 | /** 74 | * get entity's balance 75 | * 76 | * @return mixed 77 | */ 78 | public function balance() 79 | { 80 | return Ledger::balance($this); 81 | } 82 | 83 | /** 84 | * transfer amount from entity to each recipient 85 | * 86 | * @param $to 87 | * @param $amount 88 | * @param $reason 89 | * @return mixed 90 | */ 91 | public function transfer($to, $amount, $amount_currency="UGX", $reason) 92 | { 93 | return Ledger::transfer($this, $to, $amount, $amount_currency, $reason); 94 | } 95 | } --------------------------------------------------------------------------------