Prestashop Currency issue when try to get it using webservice - web-services

From Prestashop admin I have added new currency (currency which display values with comma like 26,51) and place an order. It shows prices in new currency (see image 1) but when I get order using web service, It does not get price in new currency with comma, It shows in dots instead of comma. (see image 2)

In PrestaShop database, the price values are stored as actual values (float numbers). To show them at any interface, PrestaShop passes the values to a predefined function and then display the output of that function only.
The function that Prestashop uses is
Tools::displayPrice()
You can also use it to convert the actual float value to the proper formatted currency value.

You would need to preprocess the value you get from the web service to apply the appropriate locale language:
$locale = ( isset($_COOKIE['locale']) ) ?
$_COOKIE['locale'] :
$_SERVER['HTTP_ACCEPT_LANGUAGE'];
function number_format_locale($number,$decimals=2) {
$locale = localeconv();
return number_format($number,$decimals,
$locale['decimal_point'],
$locale['thousands_sep']);
}
Use the function number_format_locale() to convert the total price to French.
French: bonne chance!

You can make a custom method that returns the value as you want, make an override of Order class (create a new php file in prestashop/override/classes/order named Order.php):
class Order extends OrderCore{
public function __construct($id = null, $id_lang = null){
$this->webserviceParameters['fields']['total_paid'] = array(
'getter' => 'getWsTotalPaid'
);
parent::__construct($id, $id_lang);
}
public function getWsTotalPaid(){
return str_replace('.', ',', $this->total_paid);
}
}
Obviously you can 'reformat' all fields that you want, but pay attention to parent settings.

Related

Simple search in Sitecore

Using Sitecore 8.2 with MVC.
I'm trying to implement the search functionality in a MVC view. (with a textbox and submit button)
There is a folder in the content tree called Books which has a list of items. Each item will have these fields - Title, Author, Price
When user searches for a term, it will be checked for a match with any of the 3 fields of the item and return the results.
This method is not working as it returns null Item.
public PartialViewResult GetSearchBooks(string txtSearch)
{
string index = string.Format("sitecore_{0}_index", Sitecore.Context.Database.Name);
List<SearchResultItem> query;
List<Item> matches = new List<Item>();
using (var context = ContentSearchManager.GetIndex(index).CreateSearchContext())
{
query = context.GetQueryable<SearchResultItem>()
.Where(p => p.Path.StartsWith("/sitecore/content/Book")).ToList();
}
foreach(SearchResultItem sritem in query)
{
Item item = sritem.GetItem(); //item is null here
if(item.Fields["Title"].Value.Contains(txtSearch) ||
item.Fields["Title"].Value.Contains(txtSearch) ||
item.Fields["Title"].Value.Contains(txtSearch))
matches.Add(item);
}
return(matches);
}
Is it the right approach. If not please suggest one.
Paths
Avoid querying the path like this:
context.GetQueryable<SearchResultItem>()
.Where(p => p.Path.StartsWith("/sitecore/content/Book"));
Instead use
context.GetQueryable<SearchResultItem>()
.Where(p => p.Paths.Contains(idOfBookFolderItem));
For more info on why, see http://blog.paulgeorge.co.uk/2015/05/29/sitecore-contentsearch-api-filtering-search-on-folder-path/
Approach
You need to hand the entire query to the search api in one go.
List<SearchResultItem> matches;
using (var context = ContentSearchManager.GetIndex(indexName).CreateSearchContext())
{
var predicate = PredicateBuilder.True<SearchResultItem>();
// must have this (.and)
predicate = predicate.And(p => p.Paths.Contains(bookFolderItem.ID));
// must have this (.and)
predicate = predicate.And(p => p.Name == searchTerm);
matches = context.GetQueryable<SearchResultItem>().Where(predicate).ToList();
}
This returns SearchResultItems not Items. If you need the item, just call GetItem.
Matches[i].GetItem()
Null items
This may indicate that your index is out of sync with the database. Try re-indexing from control panel, or in the case of the web database, REpublish the expected content.
Searching template fields
This just searches against the item name. You're limited to being able to specify the generic fields in SearchResultItem class. If you want to search specific fields on items, you can inherit from SearchResultItem and add those fields.
public class BookSearchResultItem : SearchResultItem
{
[IndexField("Book Title")]
public string BookTitle { get; set; }
[IndexField("Book Author")]
public string BookAuthor { get; set; }
}
You can then pass this into the query and search on those fields
List<BookSearchResultItem> matches;
using (var context = ContentSearchManager.GetIndex(indexName).CreateSearchContext())
{
var predicate = PredicateBuilder.True<BookSearchResultItem>();
// must have this (.and)
predicate = predicate.And(p => p.Paths.Contains(bookFolderItem.ID));
// must have this (.and)
predicate = predicate.And(
PredicateBuilder.False<BookSearchResultItem>() // in any of these fields
.Or(p => p.BookTitle == searchTerm)
.Or(p => p.BookAuthor == searchTerm)
.Or(p => p.Name == searchTerm));
matches = context.GetQueryable<BookSearchResultItem>().Where(predicate).ToList();
}
Searching all 'content'
If you find that having to specify the explicit fields is an unwanted hassle or you are performing searches across different templates with different fields, you can instead use the special computed 'content' field which combines all the text data from an item into one indexed field. So instead of the original query which did this
predicate = predicate.And(p => p.Name == searchTerm);
You can instead do just use
predicate = predicate.And(p => p.Content == searchTerm);
Which will find results where the searchterm exists in any field on the item.
First, did you check "query" contains any result?
I would suggest performing the following search query:
query = context.GetQueryable<SearchResultItem>()
.Where(p => p.TemplateId == yourBookItemTemplateID &&
(p.Fields["Title"].Value.Contains(txtSearch) ||
p.Fields["Author"].Value.Contains(txtSearch) ||
p.Fields["Price"].Value.Contains(txtSearch));
return query.Select(x => x.GetItem());
i would not suggest this approach to use. Let me explain why, or what you can do better.
First create your own Sitecore index and do not simply use the default master or web index. If you do that, you can safe the following line of code .Where(p => p.Path.StartsWith("/sitecore/content/Book")).ToList();, cause in a custom index you can simply restrict, what exactly is crawled.
Second you should never access the Sitecore item out of the search results. Reasons for that is the performance. Item item = sritem.GetItem(); You use a search, because its a performant way to access a huge amount of data. When you now access for every result the Sitecore item from the database, you lose your benefit of using a search.
You should simply use the Result Type, in your case the basic SearchResultItem. At the End of your filtering you should call something like var results = query.GetResults(); instead of accessing the items directly.
Here I found a simple example of a sitecore search, with custom index and without accessing the items directly, maybe this helps you.
http://www.mattburkedev.com/sitecore-7-contentsearch-tips/
Now to your problem.
Did you debug the search and looked into the rest of the fields of sritem? Are they all filled? If i remember correctly there is a property which stores the itemId, to retrieve the item with GetItem(). Maybe you could give us the values of the property while trying to retrieve the item.
Sometimes when the index is out of date, the returned search items may no longer exist in your content tree, So rebuild the index and try the search again,
Couple of enhancements that you can apply to your search:
As mentioned in Christian answer you can create index for just your Books tree, which means to set the root of the index to the Books root item.Web index usually used for full site content search.
Instead of getting all books items then go through all items; you can use predicates instead; even after you create the new index use the predicates to get the desired items only.
Also if your site is multilingual add a predicate to filter the required language else you will get multiple versions of the same item.

Ordering Sitecore search results

I have a IQueryable<T> object as search results object.
I apply the filtering and sorting on this search object.
Before I call the GetResults(), I want to order the results based on one of the field's (Fieldname - Priority) value. So for all the items in the IQueryable<T> object, I want to order them desc by Priority field, so all the items which has a value for that field stay at the top and the rest are at the bottom.
I have the fieldmap entry for Priority field.
search.OrderByDescending(i => !string.IsNullOrEmpty(i.GetItem().GetFieldValue("Priority")))
The above command doesn't work. Apparently, I can't use Sitecore extension methods with IQueryable?
If I convert search.ToList(). Do the ordering and then convert it back to AsQueryable(), I get the following error:
There is no method 'GetResults' on type 'Sitecore.ContentSearch.Linq.QueryableExtensions'
that matches the specified arguments
Is there a neat and quick way to get around this?
Cheers
I think you just need to add your field to your SearchResultItem and mark it as an int. I am making the assumption that the field is an int. Make a custom class that inherits SearchResultItem.
public class CustomSearchResultItem : SearchResultItem
{
[IndexField("Priority")]
public int Priority { get; set; }
}
Then use it in your search. Finally order by it.
using (var context = ContentSearchManager.GetIndex("sitecore_master_index").CreateSearchContext())
{
var results = context.GetQueryable<CustomSearchResultItem>().Where(prod => prod.Content.Contains("search box text").OrderByDescending(t => t.Priority);
}
Some data found here.
http://www.sitecore.net/learn/blogs/technical-blogs/sitecore-7-development-team/posts/2013/10/sorting-and-ordering-results.aspx
You can order search results using multiple fields by using the OrderByDescending combined with ThenByDescending. So you would need to order by Priority and then by [Name|Date|Whatever].
I want to order them desc by Priority field, so all the items which has a value for that field stay at the top and the rest are at the bottom.
I sort them first on the criteria chosen by the user - like Name, Date created etc. Once I get the results back, I need to order them by priority field
You are conflicting yourself in the questions and comments. If you want the results with priority first and then by user selected results then the following will work:
query = dataQuery.OrderByDescending(i => i.Title).ThenByDescending(i => i["Priority"]);
var results = query.GetResults().Hits.Select(h => h.Document);
There was a bug in earlier version of Sitecore which meant that the ThenBy clause will be added before the OrderBy clause hence it is added in reverse above. You may want to check if this is fixed in the current version. If so simply change your query to:
query = dataQuery.OrderByDescending(i => i["Priority"]).ThenByDescending(i => i.Title);
You don't have to add the field to your SearchResultItem if you just want to order by it, only if you need the actual value of that field returned to as well.
If you need to order by a custom user supplied value then you can pass in i => i["whatever-field-the-user-has-selected"] instead of i.Title.
You can find more info in this blog post.

how to display different price for same product in opencart?

Want to display different prices for a same product. Multiple sellers will be selling the same product with their respective prices is what I want to display if someone views a product....
If I understand you, It's not a coding case.
1 - go to Admin/Sales/Customers/Customers Group, and create as many groups as you want.
2 - go to Admin/Catalog/Products and edit an exiting product or create a new product. in Special tab you can assign different prices for each group created on step 1.
My first thought is to make them separate products, however you might want to display a product on a single page with a list of sellers to choose from, in which case...
The different sellers are product options!
The way I have set this up is by adding fields for them in the SQL products table such as price_a, price_b, price_c and then adding another field to the customers table called price_category with the relevant prefix (A,B,C). Then I wrote a function under getProduct (catalog/model/catalog/product.php) to cater for this.
The reason I took this route is because my files are uploaded automatically to the table and links to another program which generates invoices and sends the result back to the website automatically.
My Function is as follows:
if ($query->rows) {
foreach ($query1->rows as $row) {
$price_category = strtolower($row['price_category']);
$debtor_class = $row['debtor_class'];
$price_percentage = $row['price_percentage'];
}
} else {
$price = ($query->row['discount'] ? $query->row['discount'] : $query->row['price']);
$special = $query->row['special'];
}
$product_special_query = $this->db->query("SELECT price, to_qty, bonus_qty FROM product_special WHERE debtor_class = '".$debtor_class."' AND product_id = '".(int)$product_id."' AND customer_group_id = '".(int)$customer_group_id. "'");

Any API to read Engagement Values?

I am working on a solution where I need to read engagement values based on traffic types.
I tried with database query and it's working for me please see below code.
double totalValue = 0;
using (SqlConnection newCon = new SqlConnection(ConfigurationManager.ConnectionStrings["Analytics"].ConnectionString))
{
SqlCommand newCmd = new SqlCommand("SELECT SUM(Value) FROM Cache_TrafficByDay as totalValue WHERE (TrafficType = 20)", newCon);
newCon.Open();
SqlDataReader dr = newCmd.ExecuteReader();
while (dr.Read())
{
totalValue = Convert.ToDouble(dr[0]);
}
newCon.Close();
lblValue.Text = totalValue.ToString();
newCmd.ToString();
}
But I didn't find any API to do this where I can pass traffic type value and based on this traffic type value I can read engagement values.
Is there any direct method to read engagement values by passing traffic types?
Any help?
-Thanks,
Yogesh
The most recent Engagement Analytics API Reference (for 6.5 or later) doesn't list any obvious choices for accessing engagement value by traffic type.
It does however provide Sitecore.Analytics.Data.DataAccess.DataAdapters.SqlBase
This is an abstract class which contains methods to build custom queries.
Edit to provide code example:
string query ="SELECT SUM {0}Cache_TrafficByDay{1}.{0}Value{1} from {0}Cache_TrafficByDay{1} WHERE {0}Cache_TrafficByDay{1}.{0}TrafficType{1} = 20"
Double totalValue = DataAdapterManager.Sql.ReadOne<Double>(query, reader =>DataAdapterManager.Sql.GetDouble(0, reader),new object[0]);
I've not tested this, I've merely edited one of the example queries provided in the doumentation (see link above), and I'm not sure which method of ReadOne or ReadMany you need to do a SUM. You might also need to return a string using .GetString and cast it to a double yourself.

Unable to access set within set | C++

I have a class named "Store", it has 2 data fields of type "set": "customers" (of type std::set) and "albums" (of type std::set<Album>).
std::set<Album> albums;
std::set<Customer> customers;
Now, when I try to save data to one of those sets - everything works fine , but in the type "Customer" I have a third set named orders ( of type std::set ), and when I try to save data to it (and after I leave the function that saves the data) it disappears!
here is how I save the data to it:
Customer foundCustomer = *Customer::findID(customers ,id);
Order newOrder = Order();
newOrder.ordNum = ordNum;
newOrder.isPaid = false;
foundCustomer.orders.insert(newOrder);
tell me if you need me to post more code.
Help would be much appreciated !
Customer foundCustomer = *Customer::findID(customers ,id);
This line makes a copy of the customer. If you want to modify the original customer int he set, you would need to use a reference:
Customer& foundCustomer = *Customer::findID(customers ,id);
And make sure that *Customer::findID(...) results in a reference as well.