Laravel - Sums, Complex Relationships and Models Issue - laravel

I've got a customer index table that I would like to be able to show the current balance a customer has by comparing the payments made to bills against their total, and then sum up all of the remaining amounts.
At the moment my customer model looks like this (specifically for this question):
public function billToShipments()
{
return $this->hasMany(Shipment::class, 'bill_to');
}
and then my shipment model looks like this (in relation to the payment distributions):
public function paymentDistributions(){
return $this->hasMany('App\Payments_Distribution', 'shipment_id','pro_number');
}
These are the necessary fields related to this specific question:
Under Payment Distributions
-pro_number
-amount (of distribution)
Under Shipments
-balance_due
-bill_to (which is the customer id)
What I'd like to be able to do is get the sum of all balance_due's of bills that have less payment_distributions than the balance due for the customer.
For example, in the shipments (pretend under one customer):
SHIPMENT ID | Balance_Due
1234 | 10.00
1235 | 20.00
1236 | 30.00
and in the payment_distributions table:
PRO_NUMBER | AMOUNT
1234 | 2.00
1234 | 4.00
1235 | 20.00
1236 | 28.00
On the customer I'd like to say that they have a $6.00 balance (because 10.00 minus (2.00 plus 4.00) equals 4.00 for shipment # 1234, $20.00 pays off shipment #1235 completely and 2.00 remains for shipment #1236.
Again, I'd like to use the balance in a table of customers (under an #foreach statement) to give a balance sheet.
---- Updated for Jonas ----
This is how at the moment I grab remaining sums on a one record view for a customer, I pass the following to the view from the controller:
$invoicesOpen = Shipment
::whereRaw('balance > (SELECT IFNULL(SUM(payments_distributions.amount),0) FROM payments_distributions WHERE payments_distributions.shipment_id = pro_number)')
->where('bill_to','=',$customer->id)
->whereNotIn('shipment_billing_status', [2,3])
->orderBy('created_at','desc')->get();
At this point I can see that the customer has $1172.60 remaining, but through Jonas' suggestion, I somehow get -$5477.90
Now there is a closed invoice total that I can get which is currently at $5240.30. This last number is here solely to show that I'm not sure how Jonas' total is calculated.

Add this to your Customer model:
public function getBalanceAttribute() {
$toPay = $this->sum($this->billToShipments->pluck('balance_due'));
$payments = $this->billToShipments->pluck('paymentDistributions')->collapse();
$paid = $this->sum($payments->pluck('amount'));
return bcsub($toPay, $paid, 2);
}
protected function sum($values) {
return $values->reduce(function($carry, $item) {
return bcadd($carry, $item, 2);
}, '0');
}
Then use it like this:
$customers = Customer::with('billToShipments.paymentDistributions')->get();
foreach($customers as $customer) {
// $customer->balance
}

Related

Laravel: Sum column based on relationship condition

Let's say we have two tables:
Payments
id
reason_id
amount
1
1
100
2
2
10
3
1
30
Payment Reasons
id
title
is_discount
1
Payment for something
0
2
Discount for something
1
I'd like to query payments table and sum amount column based on its relationship payment_reasons.is_discount value:
total_received
total_discounted
130
10
How to achieve this?
If you want to get the data in one db-request, I don't think there is a clean laravel-way to solve this. I've been trying out some raw mysql to get it into a working query and it would look like this:
select
sum(if(pr.is_discount = 0, p.amount, 0)) as total_received,
sum(if(pr.is_discount = 1, p.amount, 0)) as total_discounted
from payments p
join payment_reasons pr on pr.id = p.reason_id
The if statement will render if discount needs to be used per row and the sum wil simply sum all the end-results together.
Doing this in laravel with a model does not really make sence, since there are no fields in the result which your model could use anyway. In this case, using eloquent would be more (unmaintainable) code than a simple Query Builder:
$data = DB::select('
select
sum(if(pr.is_discount = 0, p.amount, 0)) as total_received,
sum(if(pr.is_discount = 1, p.amount, 0)) as total_discounted
from payments p
join payment_reasons pr on pr.id = p.reason_id
')
If you don't mind doing multiple queries to fetch the data, models make more sense:
$totalReceived = Payment
::whereHas('paymentReason', fn($q) => $q->where('is_discount', 0))
->sum('amount');
$totalDiscounted = Payment
::whereHas('paymentReason', fn($q) => $q->where('is_discount', 1))
->sum('amount');
Please note that this example will perform 4 queries, 2 on payments, and 2 on payment_reasons

Laravel: How to calculate sum of column values using eloquent?

I'm trying to use sum() get the sum of column value, but unfortunately it isn't working and I can't figure out where I am wrong.
$total = Invoice::where('status', 'Completed')
->sum('amount');
This returns error Call to a member function first() on string
invoices (Table)
id
code
status
amount
1
000001
Completed
300.00
2
000002
Completed
500.00
3
000003
Pending
100.00
I want to display the sum of invoices' amount in the view.
Blade View
Activity
Count
Total Amount
Invoices
6
900.00
try this:
$total = Invoice::select(
DB::raw(SUM(amount) as total_amount)
)->where('status', 'Completed')->pluck('total_amount');
and foreach the value in the view file like:
#foreach(total as total_value)
<td>{{total_value}}</td>
#endforeach
convert the `amount` attribute into Int before storing into database.for example
$amount = $request->amount;
$invoice = new Invoice();
$invoice->amount = (int)$amount;
--
--
--
$invoice->save();
then you can use the above query for column sum

Magento Shopping Cart Rule - Is this combination possible

Hoping some one can help me with a Magento Rule - is this rule even possible
I have numerous products of numerous sizes all part of the same category.
Each product regardless of size costs £3.98 - If a buyer buys 3 products of the same category regardless of the product or size they get it for £9.99. If they buy 4 products, they get 3 of them for 9.99 but pay full price for the 4th...Every group of 3 is £9.99
I have a rule created that seems to work perfect if a Customer buys 3 / 6 / 9 items of the same product and same size...However if they mix and match it doesn't work (though they are the same category)
The rule is:
IF ALL of these conditions are TRUE:
If total quantity equals or greater than 3 for a subselection of items in cart matching ALL of these conditions:
Category is 4
I have also set the Discount Qty Step to be 3
* UPDATE *
Thanks for your reply - I have tried to implement what you suggest and have got so far as to where I get the category id of the added products. I'm unsure how to set the price the previous products so it will be an automatically discounted price
$quote = Mage::getSingleton('checkout/session')->getQuote();
$cartItems = $quote->getAllVisibleItems();
$itemPrice = "3.33";
foreach ($cartItems as $items) {
$product = $items->getProduct();
$prodCats = $product->getCategoryIds();
if (in_array('4', $prodCats)) {
$itemQty = $items->getQty();
}
$totalItems += $itemQty;
}
So what I want to do is apply a discount for multiple of 3's for any product that has a category_id of 4...The price will be 3.33 instead of the normal 3.99
You need event - observer approach for this, that will give you the flexibility you need. You can build an observer that catches the add-to-cart event sales_quote_add_item and put your logic there.
Following code within your observer function will point you in the right direction:
// Get products in cart:
$quote = Mage::getSingleton('checkout/session')->getQuote();
$cartItems = $quote->getAllVisibleItems();
foreach ($cartItems as $item) {
$itemSku = $item->getSku();
$itemQty = $item->getQty();
}
// Added product:
$item = $observer->getEvent()->getQuoteItem();
$itemQty = $item->getQty();
$itemSku = $item->getSku();
// Change price of added product:
$item->setOriginalCustomPrice($newPrice);
Good luck!

Nested Query or Sub query linq

I have two classes. Bills and Transactions. One bill is made up of many transactions. I am able to display bills and I am able to display transactions on their own. But I would like to display the last 10 bills (this part is done), but each bill should show all its transactions.
This part of the code is used to get all transactions of a bill
{ Bill bill = (Bill)Bills.Instance.GetBillsByCustomerID(id);
//get all transactions of bill
var transactions = from t in this._entities.Transactions
where t.Bill.bID == bill.bID
select new
{
t.Product.pName, t.tQty, t.tUnitPrice, t.Bill.bTotal, t.Bill.bTimestamp, t.Bill.bCustomerIDF
};
}
Now I would like that the following query below, would have some sort of nested query where all transactions OF EACH BILL are obtained: (at the moment, this only displays 10 bills - and no transactions
{
//returns top 10
var bills = (from b in this._entities.Bills
where b.bCustomerIDF == id
orderby b.bTimestamp descending
select new { b.bTotal, b.bTimestamp, b.Customer.cName}).Take(10);
return bills;
}
Can you please guide me to a simple solution? Thank you
I believe you want a join with an into
var bills = (from b in this._entities.Bills
join t in this._entities.Transactions on t.Bill.bID equals b.bID into tg
where b.bCustomerIDF == id
orderby b.bTimestamp descending
select new
{
b.bTotal,
b.bTimestamp,
b.Customer.cName,
Transactions = tg
}
).Take(10);
return bills;
I would have thought that you should just be able to add something like the following into your select:
transactions.Where(x=>x.Bill.bID == b.bID)`
That having been said I do also think it sounds like your object model is wrong. I'd have expected a Bill to have a collection of Transactions that are on that Bill.

question on linq select join

I would like to list out all the students who have yet to pay off their course fee
i.e. when a student is clicked, list out all pending fees by months.
This is what I have done so far..
These are all the students active courses.
Below are the payments record paid by student to their course.
Now i would like to list out all the pending payment foreach students
e.g. last payment to the course is on 2/11/2011. If the datetime now is May, Then i would like to show the pending amount as
Month Amount
March 100
April 200
May 400
This is what I tried..
foreach (var result in activeCourses)
{
//Show all the pending paid coures from dateJoin till datetime.Now
DateTime JoinedDate = Convert.ToDateTime(result.cus.Date);
for (DateTime d = JoinedDate; d.Month <= DateTime.Now.Month; d = d.AddMonths(1))
{
Payment payment = new Payment();
payment.Course.Id = result.c.Id;
payment.Course.Name = result.c.Name;
payment.Course.Fee = result.c.Fee;
payment.CourseByStudent.CourseUserStatus.Date = result.cu.Date;
payment.CourseByTutor.TutorId = result.t.TutorId;
payment.User.Name = result.u.Name;
payment.MonthId = d.Month;
payment.MonthToPay = d.ToString("MMM");
output.Add(payment);
}
}
The logic given above does not seem to be efficient in case the student does not pay anything for his courses, then I have to check the pending payment since his first JoinedDate. OtherWise I need to check the pending payment from the DateIssue in the Payment table according to that particular course..please advice thanks
i will use back the same approach to show the late payment.
for (DateTime d = lastPaidDate.AddMonths(1); d.Month <= DateTime.Now.Month; d = d.AddMonths(1))
Thanks

Resources