I want to update stock value when order will place. The challenge is that the products have different attributes place in the attribute table.
Small, Medium, Large, Extra large
I want to update the product attribute stock respectively when order is place. For example when user place order user selected products like
product_id = 1 size Small quantity is 7
So 7 quantity must be decrement from the product attribute size Small column.
Checkout
// checkout
public function checkout(Request $request)
{
if ($request->isMethod('post')) {
$data = $request->all();
DB::beginTransaction();
// Get cart details (Items)
$cartItems = Cart::where('user_id', Auth::user()->id)->get()->toArray();
foreach ($cartItems as $key => $item) {
# code...
$cartItem = new OrdersProduct;
$cartItem->order_id = $order_id;
$cartItem->user_id = Auth::user()->id;
// Get products details
$getProductDetails = Product::select('product_code', 'product_name', 'product_color')->where('id', $item['product_id'])->first()->toArray();
$cartItem->product_id = $item['product_id'];
$cartItem->product_code = $getProductDetails['product_code'];
$cartItem->product_name = $getProductDetails['product_name'];
$cartItem->product_color = $getProductDetails['product_color'];
$cartItem->product_size = $item['size'];
$getDiscountedAttrPrice = Product::getDiscountedAttrPrice($item['product_id'], $item['size']);
$cartItem->product_price = $getDiscountedAttrPrice['final_price'];
$cartItem->product_qty = $item['quantity'];
$cartItem->save();
// Want to Update the Product Attribute Table Stock
$item = new ProductsAttribute;
$item->where('product_id', '=', $item['product_id'], 'size', '=', $item['size'])->decrement('stock', $request->quantity);
}
// Insert Order Id in Session variable for Thanks page
Session::put('order_id', $order_id);
DB::commit();
}
}
When i run this code it shows me an error
InvalidArgumentException
Non-numeric value passed to decrement method.
When i enter value directly like decrement('stock', 7) it shows and error
Illuminate\Database\QueryException
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '`product_id` is null' at line 1 (SQL: update `products_attributes` set `stock` = `stock` - 7, `products_attributes`.`updated_at` = 2021-05-01 17:18:30 where size `product_id` is null)
i search alot but yet not find any solution. Please any one help
Just change the update query and make it simple and clean. The rest of the code is fine.
// Want to Update the Product Attribute Table Stock
$product_attribute = ProductsAttribute::where(['product_id' => $item['product_id'], 'size' => $item['size']])->first();
if($product_attribute){
$stock = $product_attribute->stock - (int) $request->quantity;
$product_attribute->update(['stock' => $stock]);
}
you have to warp it in an array or use two of wheres better and understandable
$item->where([
['product_id', '=', $item['product_id']],
['size', '=', $item['size']],
])->decrement('stock', (int) $request->quantity);
Or like this:
$item->where('product_id', $item['product_id'])
->where('size', $item['size'])
->decrement('stock', (int) $request->quantity);
Related
I am using laravel eager loading to load data on the jquery datatables. My code looks like:
$columns = array(
0 => 'company_name',
1 => 'property_name',
2 => 'amenity_review',
3 => 'pricing_review',
4 => 'sqft_offset_review',
5 => 'created_at',
6 => 'last_uploaded_at'
);
$totalData = Property::count();
$limit = $request->input('length');
$start = $request->input('start');
$order = $columns[$request->input('order.0.column')];
$dir = $request->input('order.0.dir');
$query = Property::with(['company','notices']);
$company_search = $request->columns[0]['search']['value'];
if(!empty($company_search)){
$query->whereHas('company', function ($query) use($company_search) {
$query->where('name','like',$company_search.'%');
});
}
$property_search = $request->columns[1]['search']['value'];
if(!empty($property_search)){
$query->where('properties.property_name','like',$property_search.'%');
}
if(!Auth::user()->hasRole('superAdmin')) {
$query->where('company_id',Auth::user()->company_id);
}
$query->orderBy($order,$dir);
if($limit != '-1'){
$records = $query->offset($start)->limit($limit);
}
$records = $query->get();
With this method I received error: Column not found: 1054 Unknown column 'company_name' in 'order clause' .
Next, I tried with following order condition:
if($order == 'company_name'){
$query->orderBy('company.name',$dir);
}else{
$query->orderBy($order,$dir);
}
However, it also returns similar error: Column not found: 1054 Unknown column 'company.name' in 'order clause'
Next, I tried with whereHas condition:
if($order == 'company_name'){
$order = 'name';
$query->whereHas('company', function ($query) use($order,$dir) {
$query->orderBy($order,$dir);
});
}else{
$query->orderBy($order,$dir);
}
But, in this case also, same issue.
For other table, I have handled this type of situation using DB query, however, in this particular case I need the notices as the nested results because I have looped it on the frontend. So, I need to go through eloquent.
Also, I have seen other's answer where people have suggested to order directly in model like:
public function company()
{
return $this->belongsTo('App\Models\Company')->orderBy('name');
}
But, I don't want to order direclty on model because I don't want it to be ordered by name everytime. I want to leave it to default.
Also, on some other scenario, I saw people using join combining with, but I am not really impressed with using both join and with to load the same model.
What is the best way to solve my problem?
I have table like: companies: id, name, properties: id, property_name, company_id, notices: title, slug, body, property_id
The issue here is that the Property::with(['company','notices']); will not join the companies or notices tables, but only fetch the data and attach it to the resulting Collection. Therefore, neither of the tables are part of the SQL query issued and so you cannot order it by any field in those tables.
What Property::with(['company', 'notices'])->get() does is basically issue three queries (depending on your relation setup and scopes, it might be different queries):
SELECT * FROM properties ...
SELECT * FROM companies WHERE properties.id in (...)
SELECT * FROM notices WHERE properties.id in (...)
What you tried in the sample code above is to add an ORDER BY company_name or later an ORDER BY companies.name to the first query. The query scope knows no company_name column within the properties table of course and no companies table to look for the name column. company.name will not work either because there is no company table, and even if there was one, it would not have been joined in the first query either.
The best solution for you from my point of view would be to sort the result Collection instead of ordering via SQL by replacing $records = $query->get(); with $records = $query->get()->sortBy($order, $dir);, which is the most flexible way for your task.
For that to work, you would have to replace 'company_name' with 'company.name' in your $columns array.
The only other option I see is to ->join('companies', 'companies.id', 'properties.company_id'), which will join the companies table to the first query.
Putting it all together
So, given that the rest of your code works as it should, this should do it:
$columns = [
'company.name',
'property_name',
'amenity_review',
'pricing_review',
'sqft_offset_review',
'created_at',
'last_uploaded_at',
];
$totalData = Property::count();
$limit = $request->input('length');
$start = $request->input('start');
$order = $columns[$request->input('order.0.column')];
$dir = $request->input('order.0.dir');
$query = Property::with(['company', 'notices']);
$company_search = $request->columns[0]['search']['value'];
$property_search = $request->columns[1]['search']['value'];
if (!empty($company_search)) {
$query->whereHas(
'company', function ($query) use ($company_search) {
$query->where('name', 'like', $company_search . '%');
});
}
if (!empty($property_search)) {
$query->where('properties.property_name', 'like', $property_search . '%');
}
if (!Auth::user()->hasRole('superAdmin')) {
$query->where('company_id', Auth::user()->company_id);
}
if ($limit != '-1') {
$records = $query->offset($start)->limit($limit);
}
$records = $query->get()->sortBy($order, $dir);
On my website, I have Submissions, and submissions can have comments.
Comments can have upvotes and downvotes, leading to a total "score" for the comment.
In this example, before passing the comments to the view, I sort them by score.
$comments = Comment::where('submission_id', $submission->id)->where('parent_id', NULL)->get();
$comments = $comments->sortByDesc(function($comment){
return count($comment['upvotes']) - count($comment['downvotes']);
});
This works fine. The higher the score of a comment, the higher it is sorted.
However, I want to paginate these results.
If I do ->paginate(10) instead get(), the following sortByDesc will only sort those 10 results.
So logically I would want to add the paginator after the sortByDesc like so:
$comments = $comments->sortByDesc(function($comment){
return count($comment['upvotes']) - count($comment['downvotes']);
})->paginate(10);
However this will return the error:
Method Illuminate\Database\Eloquent\Collection::paginate does not
exist.
as expected.
My question is, what is the alternative to using paginate in this situation?
EDIT:
When trying the response of #party-ring (and switching the double quotes and single quotes) I get the following error:
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an
error in your SQL syntax; check the manual that corresponds to your
MariaDB server version for the right syntax to use near '["upvotes"])
- count($comment["downvotes"]) desc limit 10 offset 0' at line 1 (SQL: select * from comments where submission_id = 1 and parent_id is
null order by count($comment["upvotes"]) -
count($comment["downvotes"]) desc limit 10 offset 0)
You are trying to paginate after the get, the solution i try on my website is this and it works
$users = User::where('votes', '>', 100)->get();
$page = Input::get('page', 1); // Get the ?page=1 from the url
$perPage = 15; // Number of items per page
$offset = ($page * $perPage) - $perPage;
return new LengthAwarePaginator(
array_slice($users->toArray(), $offset, $perPage, true), // Only grab the items we need
count($users), // Total items
$perPage, // Items per page
$page, // Current page
['path' => $request->url(), 'query' => $request->query()] // We need this so we can keep all old query parameters from the url
);
You could add a macro:
if (!Collection::hasMacro('paginate')) {
Collection::macro('paginate', function ($perPage = 25, $page = null, $options = []) {
$options['path'] = $options['path'] ?? request()->path();
$page = $page ?: (Paginator::resolveCurrentPage() ?: 1);
return new LengthAwarePaginator(
$this->forPage($page, $perPage)->values(),
$this->count(),
$perPage,
$page,
$options
);
});
}
Then you can use a collection to paginate your items:
collect([1,2,3,4,5,6,7,8,9,10])->paginate(5);
See Extending Collections under Introduction
Give this a try:
$comments = Comment::where('submission_id', $submission->id)
->where('parent_id', NULL)
->orderBy(DB::raw("count($comment['upvotes']) - count($comment['downvotes'])"), 'desc')
->paginate(10);`
SortBy returns a Collection, whereas you can only call paginate on an instance of QueryBuilder. OrderBy should return an instance of QueryBuilder, and you should be able to do the subtraction using a DB::raw statement.
** edit
I have just read about orderByRaw, which might be useful in this scenario:
$comments = Comment::where('submission_id', $submission->id)
->where('parent_id', NULL)
->orderByRaw('(upvotes - downvotes) desc')
->paginate(10);`
You might have to play around a bit with your subtraction above as I don't know the structure of your comments table.
A couple of links which might be useful:
laravel orderByRaw() on the query builder
https://laraveldaily.com/know-orderbyraw-eloquent/
I am trying to get a collection which has index as column values.
First level will have product_id as index and second level will have stock_date.
$data = Model::select('column1', 'product_id', 'stock_date')
->where('some condition')
->get();
$data = collect($data)->groupBy('product_id');
With the code above, I get the collection with product_id as the indexes.
I need the data of each product indexed by stock_date
If, for example, for product_id - 1, I have multiple records, I tried
$product_details = collect($data[1])->groupBy('stock_date');
But it does not index the records with stock_date further.
Need help to index them with stock_date.
possible solution.
// first index grouped by product_id
$original = Model::select('column1', 'product_id', 'stock_date')
->where('some condition')
->get()
->groupBy->product_id;
$final = collect();
// iterate through each group and
// group inner collection with 'stock_date'
// and put them back in an collecion
foreach($original as $key => $value) {
$final->put($key, $value->groupBy->stock_date);
}
Do you means these records are nested by stock_date,
and then stock_dates are nested by product_id
If it is, please try this below, the collect() method make all nested records becomes collection, you don't need to use collect() again.
$data = Model::select('column1', 'product_id', 'stock_date')
->where('some condition')
->get();
$data = collect($data)->groupBy('product_id');
$nested_products = [];
foreach($data as $product_id => $items) {
$nested_products []= $items->groupBy('stock_date');
}
Or you can try this line, it's more elegant:
collect($data)->groupBy('product_id')->transform(function($item, $k) { return $item->groupBy('stock_date');})
I am learning larvel 5.6 so I am trying to retrieve number of messages that have id larger than last_seen_id in pivot table
I have user table which have the default columns generated by:
php artisan make:auth
and messages tables which have the following columns:
id, from, message_content, group_id
and the group table have the columns:
id,type
now there is many to many relation between the users and groups table through the custom pivot table which have the columns:
group_id,user_id,last_id_seen
now if I want to retrieve the messages which belong to same group and have larger id than last_id_seen in the pivot table how to do it?
I think you are looking for something like this:
$groupId = 1; // set to whatever you want
$lastSeenId = \Auth::user()->groups()
->where('group_id', $groupId)
->first()->pivot->last_id_seen;
$messages = Message::where('id', '>', $lastSeenId)->get();
A more robust version, which does not fail when your user does not have an entry for the group yet, would be:
$groupId = 1; // set to whatever you want
$group = \Auth::user()->groups()->where('group_id', $groupId)->first();
$lastSeenId = $group ? $group->pivot->last_id_seen : null;
$messages = Message::when($lastSeenId, function($query, $id) {
$query->where('id', '>', $id);
})->get();
Note: normally you'd use optional() in the second snippet, but Laravel 5.2 does not come with this helper...
If you want both the count() of the results and the results themselves, you can store the query in a variable and perform two queries with it. You then don't have to rewrite the same query twice:
$groupId = 1; // set to whatever you want
$group = \Auth::user()->groups()->where('group_id', $groupId)->first();
$lastSeenId = $group ? $group->pivot->last_id_seen : null;
$query = Message::when($lastSeenId, function($query, $id) {
$query->where('id', '>', $id);
});
$count = $query->count();
$messages = $query->get();
I'm looking to filter a product list by those products which have a group_price set at the product level and assigned to a specific customer group.
I was thinking it would be something along the lines of:
$products->addFieldToFilter('group_price', array(
array(
'cust_group' => 2
)
));
But it appears that group_price is not an attribute. Additionally, $_product->getGroupPrice() always returns the product's price despite if a group price is set on the product or not.
Ideally, I'd prefer to filter these by the customer group code (ie. Wholesale, Retail, etc) instead of the group id (simply for the case where someone might delete a customer group and recreate it later and the id changes).
Any thoughts?
I have a similar requirement but the problem is that iterating over a large product collection is way too slow.
The catalog_product_index_price table contains group information so you may try something like:
$productCollection = Mage::getModel('catalog/product')->getCollection();
...
$productCollection->addFinalPrice();
$productCollection->getSelect()->where(
'price_index.customer_group_id = ? AND price_index.group_price IS NOT NULL',
$customer_group_id
);
I ended up using this:
$products = Mage::getModel('catalog/product')->getResourceCollection();
$products
->addAttributeToSelect('*')
->addAttributeToFilter('visibility', array('neq' => 1));
foreach ($products as $product => $value) {
//still not sure how to get 'group_price' without running load() =(
$productModel = Mage::getModel('catalog/product')->load($value->getId());
$groupPrices = $productModel->getData('group_price');
// A helper of mine
// store the customer's groupId to compare against available group prices array below.
$currentGroupId = Mage::helper('user')->getCustomerGroup()->getId();
// remove products w/o configured group prices
if (!count($groupPrices)) {
$products->removeItemByKey($product);
}
foreach ($groupPrices as $key) {
foreach ($key as $subkey => $value) {
if ($subkey == "cust_group") {
$customerGroup = $subkey;
if ($value != $currentGroupId) {
$products->removeItemByKey($product);
}
}
}
}
};
$this->_productCollection = $products;
return $this->_productCollection;