I've been searching endlessly for a clue on how I should properly go about creating a "Money Transfer" function (for a game, not real money) within Laravel 4.2.
Needlessly to say, I've come up empty handed and I'm turning to you guys.
The task:
Transfer funds from "Spending" to "Saving" accounts (or vice-versa)
Subtract the amount from the account it's exiting.
Add the amount to the account it's entering.
What I need:
A simple calculation to help me get started on building this out. I'm quite new to writing Eloquent and simply need someone to outline how this sort of thing should work.
Database:
id, user_id, spending, saving, bucks, pin, created_at, updated_at
Model:
class Bank extends Eloquent {
protected $table = 'banks';
protected $fillable = ['user_id, spending, saving, bucks, pin'];
// Connect to the User
public function user()
{
return $this->belongsTo('User');
}
}
Controller:
public function transferMoney()
{
$id = Auth::id();
$bank = Bank::find($id);
$spending = $bank->spending;
$saving = $bank->saving;
$transfer_type = Input::get('transfer_to');
$transfer_amount = Input::get('amount');
// Spending to Savings
if($transfer_type = 1) {
if($transfer_amount >= $spending) {
// the magic to transfer the funds goes here.
}
}
// Savings to Spending
if($transfer_type = 2) {
if($transfer_amount >= $savings) {
// the magic to transfer the funds goes here.
}
}
}
Form in View:
{{ Form::open(array('route' => array('transferMoney'), 'method' => 'post')) }}
{{ Form::select('transfer_to', array('1' => 'Spending to Saving', '2' => 'Saving to Spending')) }}
{{ Form::text('amount', null, ['placeholder' => 'Amount']) }}
{{ Form::submit('Transfer', array('class' => 'button secondary pull-right')) }}
{{ Form::close() }}
Route:
Route::post('/bank', array('as' => 'transferMoney', 'uses' => 'BankController#transferMoney'));
Any tips & tricks on best practices are hugely appreciated!
Apologies if this repeated - I swear I can't find a solution to this specific roadblock.
Thank you!
I believe you'll need to subtract the amount ($transfer_amount) from the transfer-er and add it to the transfer-ee
public function transferMoney()
{
$id = Auth::id();
$bank = Bank::find($id);
$transfer_type = Input::get('transfer_to');
$transfer_amount = Input::get('amount');
// Spending to Savings
if($transfer_type == 1)
{
if($transfer_amount > $bank->spending)
{
// Error - insufficient funds
}
else
{
$bank->spending -= $amount;
$bank->saving += $amount;
$bank->save();
}
}
// Savings to Spending
if($transfer_type == 2)
{
if($transfer_amount > $bank->saving)
{
// Error - insufficient funds
}
else
{
$bank->spending += $amount;
$bank->saving -= $amount;
$bank->save();
}
}
}
I also fixed a few syntactical things (if($transfer_type = 1) needs more than one =).
Make sure you validate that the transfer amount is a valid number! :)
Related
I have bank table and transaction table which has one to many relationship. I want to calculate balance of each bank and also total banks balance.
bank model:
class Bank extends Model
{
use HasFactory;
protected $fillable = [
'name',
'code',
'accountNumber',
'swiftCode',
'currency',
'country',
'city',
'street',
'zipcode',
];
public function transactions()
{
return $this->hasMany(Transaction::class);
}
}
transactions model:
class Transaction extends Model
{
use HasFactory;
protected $fillable = [
'amount',
'currency',
'exchangeRate',
'reference',
'type',
'adjustment',
'partner_id',
'bank_id',
];
public function bank()
{
return $this->belongsTo(Bank::class);
}
}
I wrote the code below for balance which is not correct yet, because I can't access transactions columns using this collection.
<td>{{$bank->transactions->where('type', 'credit')->sum('amount') - $bank->transactions->where('type', 'debit')->sum('amount')}}</td>
there are many currencies which needs to be normalized using exchangRate.
I need to multiply amount with exchangeRate and sum all it's results. so it gives bank balance.
I should pass it from index function. it should be returned with bank collection.
BankController function index:
public function index()
{
$banks = Bank::all();
return view('inc.banks', compact('banks'));
}
based on these, how can I calculate each bank balance and total banks balance?
You have to fetch it from controller and pass it to the view, Create a function to get data
//Here You will get all transactions relevant to the bank as per your relationship
$banks =Transaction::with('transactions.bank')->get();
return view('inc.banks', compact('banks'));
with the array of output you can compute manually the amounts you need, Or else you can do it manually querying it.
To get a clear picture of your output try manually querying it on database with SQL Syntax. Once you got the right SQL syntax you can go for laravel eloquent (This method will help you a lot in understanding what your doing) !! Good Luck !
You can make two relations (credits and debits) and with them, calculate the bank balances and total balance.
Bank model
public function credits(){
return $this->hasMany(Transaction::class, foreign_id, primary_id)->where('type', 'credit);
}
public function debits(){
return $this->hasMany(Transaction::class, foreign_id, primary_id)->where('type', 'debit);
}
Blade:
Initialize $total variable first. Then loop through $banks to get balance for each bank and add them up for getting total balance.
#php( $total = 0)
#foreach($banks as $key => $bank)
$balance = $bank->credits->sum('amount') - $bank->debits->sum('amount'); // $balance will have each bank balance
$total += $balance;
#endforeach
{{ $total }} // get total balance for all banks
Edit
If you want to calculate using exchangeRate on amount:
#php($total = 0)
#foreach($banks as $key => $bank)
$credits = 0;
$debits = 0;
#foreach($bank->transactions as $key => $transaction)
#if($transaction->type == 'credit')
$credits += $transaction->amount*$transaction->exchangeRate;
#elseif($transaction->type == 'dedit')
$dedits += $transaction->amount*$transaction->exchangeRate;
#endif
#endforeach
$balance = $credits-$debits;
$total += $balance;
#endforeach
{{ $total }}
I have solved this in bank and transaction model. I defined a custom attribute and then append it to model.
Transaction Model:
protected $appends = [
'final_amount'
];
public function getFinalAmountAttribute() {
return $this->amount * $this->exchangeRate;
}
Bank Model:
public function getCreditSumAttribute(){
$sum = 0;
if($this->transactions){
$sum = $this->transactions->where('type', 'credit')->sum('final_amount');
}
return $sum;
}
public function getDebitSumAttribute(){
$sum = 0;
if($this->transactions){
$sum = $this->transactions->where('type', 'debit')->sum('final_amount');
}
return $sum;
}
public function getSubCreditDebitAttribute(){
return $this->credit_sum - $this->debit_sum;
}
and in banks view I put this code:
<td>{{'$ '}}{{$bank->sub_credit_debit}}</td>
So before everything this is not duplicate.
I've got a callback method which will get 2 parameters from payment getway. the function they gave us need Amount to make sure everything is correct and base on Amount they gonna gave us payment status, but they won't post it, i should get it from my Database which i've did base on this code :
public function order(Request $request){
$MerchantID = 'xxxxxxxxxxx';
$Authority =$request->get('Authority') ;
$Amount = Invoice::select('invoice_balance')->where('authority',$Authority)->get();
if ($request->get('Status') == 'OK') {
$client = new nusoap_client('https://www.localhost.com/pg/services/WebGate/wsdl', 'wsdl');
$client->soap_defencoding = 'UTF-8';
$result = $client->call('PaymentVerification', [
[
'MerchantID' => $MerchantID,
'Authority' => $Authority,
'Amount' => $Amount,
],
]);
if ($result['Status'] == 100) {
return 'Done.';
} else {
return 'Error with 1';
}
}
else
{
return 'Error with 2';
}
// return $Amount;
}
when i use this code i get The Response content must be a string or object implementing __toString(), "boolean" given. which i'm pretty sure it's just about Amount part, because when use manual value for Amount (exact amount of cart in $Amount = amount), it's gonna gave me The Response content must be a string or object implementing __toString(), "boolean" given. Error.
I've also tried someways in other questions but didn't worked. if u remove whole if(status... part and only return $Amount to make sure it work it gonna gave [{"invoice_balance":"2000"}] which i don't know if this is my mistake or not. please help me, i'm in learning process.
Invoice Model(if needed):
class Invoice extends Model {
protected $fillable = [
'from_user_id', 'to_user_id', 'invoice_title', 'invoice_description', 'invoice_balance', 'invoice_due_date', 'status'
];
protected $hidden = [
'authority'
];
public function user()
{
return $this->belongsTo(User::class);
}
}
well the solution was changing
$Amount = Invoice::select('invoice_balance')->where('authority',$Authority)->get();
to
$Amount = Invoice::select('invoice_balance')->where('authority',$Authority)->value('authority');
Need more information:
Do this and tell me what the output is:
public function order(Request $request){
dd($request->input());
}
I have a problem with codeigniter,
I want to do a join in the addition of a carrier,
when I add I assign a truck this driver
I want the state of truck changes from 0 to 1,
but I do not know,
public function add($email, $password , $nom , $prenom , $telephone,$id_camion)
{
$query = $this->db->get_where('transporteur', array('email' => $email));
if ($query->num_rows == 1) {
return FALSE;
}
$this->db->insert('transporteur', array('email' => $email,'password' => md5($password),'nom' => $nom ,'prenom'=>$prenom ,'telephone' => $telephone,'id_camion' => $id_camion));
return TRUE;
}
If I understand your question correctly, now that you've inserted a new carrier you want to set some state in a table of trucks. You already have the truck ID as a parameter so in theory all you need to do is:
//update only on a given camion_id
$this->db->where('id', $camion_id);
$this->db->update('camions', array('state' => 1));
Here I assume your table is called camions, its ID is id and the state column you're trying to change from 0 to 1 is called state.
If that's not quite right, please update your question. If you have trouble translating it into english, I can help with that, too. ;)
I'm confused about your question but you have (num_rows should be num_rows()) following code:
if ($query->num_rows == 1) {
return FALSE;
}
It should be:
if ($query->num_rows() == 1) {
return FALSE;
}
It's a method not a property. You may also use it like this way:
if ($query->num_rows()) {
return FALSE;
}
How do I add custom sort option in Magento. I want to add Best Sellers, Top rated and exclusive in addition to sort by Price. Please help
For Best Sellers
haneged in code/local/Mage/Catalog/Block/Product/List/Toolbar.php method setCollection to
public function setCollection($collection) {
parent::setCollection($collection);
if ($this->getCurrentOrder()) {
if($this->getCurrentOrder() == 'saleability') {
$this->getCollection()->getSelect()
->joinLeft('sales_flat_order_item AS sfoi', 'e.entity_id = sfoi.product_id', 'SUM(sfoi.qty_ordered) AS ordered_qty')
->group('e.entity_id')->order('ordered_qty' . $this->getCurrentDirectionReverse());
} else {
$this->getCollection()
->setOrder($this->getCurrentOrder(), $this->getCurrentDirection());
}
}
return $this;
}
After setCollection I added this method:
public function getCurrentDirectionReverse() {
if ($this->getCurrentDirection() == 'asc') {
return 'desc';
} elseif ($this->getCurrentDirection() == 'desc') {
return 'asc';
} else {
return $this->getCurrentDirection();
}
}
And finally I changed mehod setDefaultOrder to
public function setDefaultOrder($field) {
if (isset($this->_availableOrder[$field])) {
$this->_availableOrder = array(
'name' => $this->__('Name'),
'price' => $this->__('Price'),
'position' => $this->__('Position'),
'saleability' => $this->__('Saleability'),
);
$this->_orderField = $field;
}
return $this;
}
for Top rated
http://www.fontis.com.au/blog/magento/sort-products-rating
try above code.
for date added
Magento - Sort by Date Added
i am not associate with any of the above link for any work or concern it is just for knowledge purpose and to solve your issue.
hope this will sure help you.
Thanks for your answer, Anuj, that was the best working module I could find so far.
Just add an extra bit to your code in order to solve no pagination caused by 'group by'
Copy '/lib/varien/data/collection/Db.php'
To 'local/varien/data/collection/Db.php'.
Change the getSize function to
public function getSize()
{
if (is_null($this->_totalRecords)) {
$sql = $this->getSelectCountSql();
//$this->_totalRecords = $this->getConnection()->fetchOne($sql, $this->_bindParams); //============================>change behave of fetchOne to fetchAll
//got array of all COUNT(DISTINCT e.entity_id), then sum
$result = $this->getConnection()->fetchAll($sql, $this->_bindParams);
foreach ($result as $row) {//echo'<pre>'; print_r($row);
$this->_totalRecords += reset($row);
}
}
return intval($this->_totalRecords);
}
Hope it could help anyone.
update
The filter section need to be updated as well, otherwise just showing 1 item on all filter.
and the price filter will not be accurate.
What you need to do it to modify core/mage/catalog/model/layer/filter/attribute.php and price.php
attribute.php getCount() on bottom
$countArr = array();
//print_r($connection->fetchall($select));
foreach ($connection->fetchall($select) as $single)
{
if (isset($countArr[$single['value']]))
{
$countArr[$single['value']] += $single['count'];
}
else
{
$countArr[$single['value']] = $single['count'];
}
}
//print_r($countArr);//exit;
return $countArr;
//return $connection->fetchPairs($select);
Price.php getMaxPrice
$maxPrice = 0;
foreach ($connection->fetchall($select) as $value)
{
if (reset($value) > $maxPrice)
{
$maxPrice = reset($value);
}
}
return $maxPrice;
If you are having the same problem and looking for the question, you will know what I meant.
Good luck, spent 8 hours on that best sell function.
Update again,
just found another method to implement
using cron to collect best sale data daily saved in a table that includes product_id and calculated base sale figure.
then simply left join, without applying 'group by'
that means core functions do not need to changed and speed up the whole sorting process.
Finally finished! hehe.
To sort out pagination issue for custom sorting collection rewrite the resource model of it's collection from
app\code\core\Mage\Catalog\Model\Resource\Product\Collection.php
And modify below method from core
protected function _getSelectCountSql($select = null, $resetLeftJoins = true)
{
$this->_renderFilters();
$countSelect = (is_null($select)) ?
$this->_getClearSelect() :
$this->_buildClearSelect($select);
/*Added to reset count filters for Group*/
if(count($countSelect->getPart(Zend_Db_Select::GROUP)) > 0) {
$countSelect->reset(Zend_Db_Select::GROUP);
}
/*Added to reset count filters for Group*/
$countSelect->columns('COUNT(DISTINCT e.entity_id)');
if ($resetLeftJoins) {
$countSelect->resetJoinLeft();
}
return $countSelect;
}
Above will solve count issue for custom sorting collection.
I'm creating a payment form with symfony 1.4 , and my form has a date widget defined like this, so that the user can select the expiration date of his credit card:
new sfWidgetFormDate(array(
'format' => '%month%/%year%',
'years' => array_combine(range(date('Y'), date('Y') + 5), range(date('Y'), date('Y') + 5))
Notice the absence of %day% in the format like in most payment forms.
Now my problem is that sfValidatorDate requires the 'day' field not to be empty. To work around this, I created a custom validator using a callback, which works well:
public function validateExpirationDate($validator, $value)
{
$value['day'] = '15';
$dateValidator = new sfValidatorDate(array(
'date_format' => '#(?P<day>\d{2})(?P<month>\d{2})(?P<year>\d{2})#',
'required' => false,
'min' => strtotime('first day of this month')));
$dateValidator->clean($value);
return $value;
}
I feel there might be a simpler way to achieve this. What do you think? Have you already solved this problem in a cleaner way?
How do you store the date? If you just store month and year as integers or strings, then you can just make 2 choice widgets. But if you store it as datetime (timestamp), then you need a valid date anyway. This means that you need to automatically assign values to 'day' (usually first or last day of the month).
class YourForm extends BaseYourForm
{
public function configure()
{
$this->widgetSchema['date'] = new sfWidgetFormDate(array(
'format' => '%month%/%year%'
));
$this->validatorSchema['date'] = new myValidatorDate(array(
'day_default' => 1
));
}
}
class myValidatorDate extends sfValidatorDate
{
protected function configure($options = array(), $messages = array())
{
$this->addOption('day_default', 1);
parent::configure($options, $messages);
}
protected function doClean($value)
{
if (!isset($value['day']))
{
$value['day'] = $this->getOption('day_default');
}
return parent::doClean($value);
}
}
There's no need to use a custom validation class: you can simply override the tainted values passed to your bind() method:
<?php
// in your form class
public function bind(array $taintedValues = null, array $taintedFiles = null)
{
$taintedValues['date']['day'] = 1;
return parent::bind($taintedValues, $taintedFiles);
}
I used simplest way, for validate credit card expiration day:
$post_data = $request->getParameter('my_form');
$post_data['card_exp']['day'] = 1; //sets the first day of the month
$this->form->bind($post_data);
Hope this helps somebody.
I solve this first in the form class
$year = range(date('Y'), date('Y') - 50);
$this->widgetSchema['date'] = new sfWidgetFormDate(array(
'format' => '%year%',
'years' => array_combine($year, $year),
'can_be_empty' => false
));
Next...
public function bind(array $taintedValues = null){
$taintedValues['date']['day'] = '01';
$taintedValues['date']['month'] = '01';
parent::bind($taintedValues);
}
The field in the database is date type DATE.