Sylius - How to assign a Channel to a Product programmatically? - symfony

I am trying to assign a Channel to my products created programmatically, so they will be displayed on shop. Unfortunately, there is no documentation for this use case.
Here is how I create my products:
$productFactory = $this->container->get('sylius.factory.product');
$productManager = $this->container->get('sylius.manager.product');
$productRepository = $this->get('sylius.repository.product');
$productVariantFactory = $this->get('sylius.factory.product_variant');
$productVariantRepository = $this->get('sylius.repository.product_variant');
$channelPricingFactory = $this->get('sylius.factory.channel_pricing');
$channelPricingRepository = $this->get('sylius.repository.channel_pricing');
//CREATE PRODUCT
$product = $factory->createNew();
$product->setName('TEST 2 - '.$title);
$product->setCode($this->generateRandomString());
$product->setSlug($this->generateRandomString());
$productRepository->add($product);
//CREATE VARIANT & ATTACH IT TO PRODUCT
$variant = $productVariantFactory->createNew();
$variant->setName('TEST 2 - '.$title);
$variant->setCode($this->generateRandomString());
$variant->setProduct($product);
$productVariantRepository->add($variant);
//CREATE PRICE & ATTACH IT TO VARIANT
$channelPricing = $channelPricingFactory->createNew();
$channelPricing->setPrice(999);
$channelPricing->setOriginalPrice(999);
$channelPricing->setChannelCode('US_WEB');
$channelPricing->setProductVariant($variant);
$channelPricingRepository->add($channelPricing);
Unfortunately, the products are not linked to a Channel:

The answer to your question:
You have one product variant, but Product variant implements ProductVariantInterface which extends TranslatableInterface. So we need one translation to make it appear and work. To add the translation:
$productVariant->setCurrentLocale('fr_FR');
$productVariantTranslation = $productVariant->getTranslation();
or
$productVariantTranslation = $productVariant->getTranslation($locale);
after you can add a name or not:
$productVariantTranslation->setName('What a product variant!');
after:
$product->addVariant($productVariant);
$this->entityManager->persist($product);
You will have your product variant on line.
Another thing is that:
$channelPricingRepository = $this->get('sylius.repository.channel_pricing');
$channelPricingRepository->add($entity);
it's going to flush directly data to DB in each call. In the example you are going to flush 3 times instead only one. In bigger proccess with many "add" this can be a lack of performance. You can simply;
$this->entityManager->persist($entity); //Many times
$this->entityManager->flush();

Here is how I managed to create my products (to attach them then to my entities):
function createProduct($livre,$options){
$title = $livre['title'];
$prix = $livre['prix'];
// SYLIUS REPOSITORIES LOAD
$productFactory = $options['sylius_factory_product'];
$productRepository = $options['sylius_repository_product'];
$productVariantFactory = $options['sylius_factory_product_variant'];
$productVariantRepository = $options['sylius_repository_product_variant'];
$channelPricingFactory = $options['sylius_factory_channel_pricing'];
$channelPricingRepository = $options['sylius_repository_channel_pricing'];
//CREATE PRODUCT
$product = $productFactory->createNew();
$product->setName($title);
$product->setCode($title.'_'.$this->generateRandomString());
$product->setSlug($title.'_'.$this->generateRandomString());
$productRepository->add($product);
//CREATE VARIANT & ATTACH IT TO PRODUCT
$variant = $productVariantFactory->createNew();
$variant->setName($title. 'Variant');
$variant->setCode($title.'_'.$this->generateRandomString());
$variant->setProduct($product);
$productVariantRepository->add($variant);
//CREATE PRICE & ATTACH IT TO VARIANT
$channelPricing = $channelPricingFactory->createNew();
$channelPricing->setPrice($prix*100);
$channelPricing->setOriginalPrice($prix*100);
$channelPricing->setChannelCode('CH');
$channelPricing->setProductVariant($variant);
$channelPricingRepository->add($channelPricing);
$productId = $product->getId();
return $productId;
}

I added the channel to the product like this:
$channelCode = 'US_WEB'
$channelRepository = $this->get('sylius.repository.channel');
$channel = $channelRepository->findOneBy(array('code' => $channelCode));
$product->addChannel($channel);

Related

How to create multi items/records or save item/record array at one time in client script file

I want to create multiple records at the same time using client script. This is what I'm doing:
var ceateDatasource = app.datasources.Reservation.modes.create;
var newItem = ceateDatasource.item;
newItem.User = user; //'eric'
newItem.Description = description; //'000'
newItem.Location_Lab_fk = lab.value.Id; //'T'
newItem.Area_fk = area.value.Id; //'L'
newItem.Equipment_fk = equipment.value.Id; //'S'
for(var i = 0 ; i < 3; i ++) {
newItem.Start_Date = startDate;
newItem.Start_Hours = '03';
newItem.Start_Minutes = '00';
newItem.End_Date = startDate;
newItem.End_Hours = '23';
newItem.End_Minutes = '30';
// Create the new item
ceateDatasource.createItem();
}
But the result I'm getting is this one:
The three records are created but the only the first one has data. The other two records have empty values on their fields. How can I achieve this?
Thanks.
Update(2019-3-27):
I was able to make it work by putting everything inside the for loop block. However, I have another question.
Is there any method like the below sample code?
var recordData = [Data1, Data2, Data3]
var ceateDatasource;
var newItem = new Array(recordData.length) ;
for(var i = 0 ; i < recordData.length; i ++) {
ceateDatasource = app.datasources.Reservation.modes.create;
newItem[i] = ceateDatasource.item;
newItem[i].User = recordData[i].user;
newItem[i].Description = recordData[i].Description;
newItem[i].Location_Lab_fk = recordData[i].Location_Lab_fk;
newItem[i].Area_fk = recordData[i].Area_fk;
newItem[i].Equipment_fk = recordData[i].Equipment_fk;
newItem[i].Start_Date = recordData[i].Start_Date;
newItem[i].Start_Hours = recordData[i].Start_Hours;
newItem[i].Start_Minutes = recordData[i].Start_Minutes;
newItem[i].End_Date = recordData[i].End_Date;
newItem[i].End_Hours = recordData[i].End_Hours;
newItem[i].End_Minutes = recordData[i].End_Minutes;
}
// Create the new item
ceateDatasource.createItem();
First, it prepares an array 'newItem' and only calls 'ceateDatasource.createItem()' one time to save all new records(or items).
I try to use this method, but it only saves the last record 'newItem[3]'.
I need to write a callback function in 'ceateDatasource.createItem()' but Google App Maker always show a warning "Don't make functions within a loop". So, are there any methods to call 'createItem()' one time to save several records? Or are there some functions like 'array.push' which can be used?
Thanks.
As per AppMaker's official documentation:
A create datasource is a datasource used to create items in a particular data source. Its item property is always populated by a draft item which can be bound to or set programmatically.
What you are trying to do is create three items off the same draft item. That why you see the result you get. If you want to create multiple items, you need to create a draft item for each one, hence all you need to do is put all your code inside the for loop.
for(var i = 0 ; i < 3; i ++) {
var ceateDatasource = app.datasources.Reservation.modes.create;
var newItem = ceateDatasource.item;
newItem.User = user; //'eric'
newItem.Description = description; //'000'
newItem.Location_Lab_fk = lab.value.Id; //'T'
newItem.Area_fk = area.value.Id; //'L'
newItem.Equipment_fk = equipment.value.Id; //'S'
newItem.Start_Date = startDate;
newItem.Start_Hours = '03';
newItem.Start_Minutes = '00';
newItem.End_Date = startDate;
newItem.End_Hours = '23';
newItem.End_Minutes = '30';
// Create the new item
ceateDatasource.createItem();
}
If you want to save several records at the same time using client script, then what you are looking for is the Manual Save Mode. So all you have to do is go to your model's datasource and click on the checkbox "Manual Save Mode".
Then use the same code as above. The only difference is that in order to persist the changes to the server, you need to explicitly save changes. So all you have to do is add the following after the for loop block:
app.datasources.Reservation.saveChanges(function(){
//TODO: Callback handler
});

Maximo Anywhere - Lookup Filter issue

I am working on Maximo Anywhere 7.5.2 (Work Execution app). I need to filter the lookup values based on some conditions within Anywhere.
Ex: Lets consider, I have textfield which can have A or B value only, If it is A from Maximo, then the lookup field should show (P,Q,R,S) and if it is B, Lookup should show (P,Q) only.
This is trickier than you think, because you'll need to write your own code to execute to filter the subsequent lookup. For an example you can look at this code in WODetailHandler.filterAssetForLookup method.
filterAssetForLookup: function(eventContext){
var additionalasset = CommonHandler._getAdditionalResource(eventContext,'additionalasset');
additionalasset._lookupFilter = null;
//save the current asset so we can reset it if the user has to revert the value
var workOrderSet = CommonHandler._getAdditionalResource(eventContext,"workOrder");
if(workOrderSet.getCurrentRecord() != null){
this.curAsset = workOrderSet.getCurrentRecord().get("asset");
this.curAssetDesc = workOrderSet.getCurrentRecord().get("assetdesc");
this.curAssetld = workOrderSet.getCurrentRecord().get("assetld");
}
var siteid = CommonHandler._getWorkorderSiteId(eventContext);
if(siteid == null){
siteid = UserManager.getInfo("defsite");
}
var filter = [];
filter.push({siteid: siteid});
additionalasset.lookupFilter = filter;
},
Then you attach this filter in the filterMethod in the app.xml.
<lookup filterClass="application.handlers.WODetailHandler" filterMethod="filterAssetForLookup" id="WorkExecution.AssetLookup" label="Select Asset" resource="additionalasset">

How to get spcial item in QuickBooks online by Programming

I've inserted three Customer items into QuickBooks online. I want to find a special item by ids and modify one of the attributes' value. I want to accomplish this by coding in backstage of a application. How can I do this?
This is the connection code that I have:
realmId = HttpContext.Current.Session["realm"].ToString();
accessToken = HttpContext.Current.Session["accessToken"].ToString();
accessTokenSecret = HttpContext.Current.Session["accessTokenSecret"].ToString();
consumerKey = ConfigurationManager.AppSettings["consumerKey"].ToString(CultureInfo.InvariantCulture);
consumerSecret = ConfigurationManager.AppSettings["consumerSecret"];
dataSourcetype = IntuitServicesType.QBO;
OAuthRequestValidator oauthValidator = new OAuthRequestValidator(accessToken, accessTokenSecret, consumerKey, consumerSecret);
ServiceContext context = new ServiceContext(oauthValidator, realmId, dataSourcetype);
DataServices commonService = new DataServices(context);
You can query for customers as follows:
//search based on customer name
var qbdCustomerQuery1 = new Intuit.Ipp.Data.Qbd.CustomerQuery();
qbdCustomerQuery1.Item1ElementName = Intuit.Ipp.Data.Qbd.Item1ChoiceType.FirstLastInside; //Item1ChoiceType.FirstLastEnd //Item1ChoiceType.FirstLastStart
qbdCustomerQuery1.Item1 = "Popeye";
List<Intuit.Ipp.Data.Qbd.Customer> CustomerQueryResult = qbdCustomerQuery1.ExecuteQuery<Intuit.Ipp.Data.Qbd.Customer>(context).ToList<Intuit.Ipp.Data.Qbd.Customer>();
//search based on customer id
Intuit.Ipp.Data.Qbo.Customer qboCustomer = new Intuit.Ipp.Data.Qbo.Customer();
qboCustomer.Id = new IdType() { idDomain = Intuit.Ipp.Data.Qbo.idDomainEnum.QBO, Value = "3" };
IEnumerable<Intuit.Ipp.Data.Qbo.Customer> qboCustomerResults = commonService.FindById(qboCustomer) as IEnumerable<Intuit.Ipp.Data.Qbo.Customer>;
Use the resultset to get the customer object. Modify the values and call Update:
https://developer.intuit.com/docs/0025_quickbooksapi/0055_devkits/0100_ipp_.net_devkit/0299_synchronous_calls/0001_data_service_apis

How to Advance filter for category and author in Smartsearch in kentico

I have created basic search and uses the SearchHelper to get smart search results based on the search paramaters.
Now creating the Advance search based on Category , Author etc but did not find the way to filter the result based on these condition.
I am looking for a way to display the results using the dataset that
// Prepare parameters
SearchParameters parameters = new SearchParameters()
{
SearchFor = searchText,
SearchSort = SearchHelper.GetSort(srt),
Path = path,
ClassNames = DocumentTypes,
CurrentCulture = culture,
DefaultCulture = defaultCulture,
CombineWithDefaultCulture = CombineWithDefaultCulture,
CheckPermissions = CheckPermissions,
SearchInAttachments = SearchInAttachments,
User = (UserInfo)CMSContext.CurrentUser,
SearchIndexes = Indexes,
StartingPosition = startPosition,
DisplayResults = displayResults,
NumberOfProcessedResults = numberOfProceeded,
NumberOfResults = 0,
AttachmentWhere = AttachmentsWhere,
AttachmentOrderBy = AttachmentsOrderBy,
BlockFieldOnlySearch = BlockFieldOnlySearch,
};
// Search
DataSet results = SearchHelper.Search(parameters);
The easiest way is to use the method:
SearchHelper.CombineSearchCondition()
The first parameter is the searchText, with the search terms you probably already have.
The second parameter is searchConditions, which can be formatted as per https://docs.kentico.com/k10/configuring-kentico/setting-up-search-on-your-website/smart-search-syntax
Alternatively you could just append your search conditions to your search text manually, separating each term with a space.
Remember that to filter based on any field they need to be selected as searchable in the SiteManager->Development->DocumentTypes->DocumentType->Search Tab.

Entity Framework nested lambda query

In Linq2Sql, it was possible to do a query such as:
using (var db = GetDataContent())
{
var query = from p in db.Brands
where p.Deleted == false
select new BrandImageSummary
{
BrandID = p.BrandID,
BrandUrl = p.BrandUrl,
Description = p.Description,
MetaDescription = p.MetaDescription,
MetaKeywords = p.MetaKeywords,
MetaTitle = p.MetaTitle,
BrandImageUrl = (from p2 in db.SiteImages where p2.FileTypeID == 5 && p2.ForeignID == p.BrandID && p2.Deleted == false orderby p2.Rank select p2.Filename).FirstOrDefault(),
Deleted = p.Deleted,
SupplierCode = p.SupplierCode,
Title = p.Title,
Website = p.Website
};
return query.ToList();
}
With BrandImageUrl being a nested select. Howerver in entity framework, I seem to get the error:
Unable to create a constant value of type 'SiteImage'. Only primitive
types or enumeration types are supported in this context.
Is there a way to do this in entity framework?
The idea of the query is to get one brand image, if I was to join, and there was multiple images, I would get multiple rows and I do not want this.
I am using Entity Framework 5.
Thanks for your help
You should create a one-to-many relation in your model classes.
You can then write
BrandImageUrl = p.BrandImages
.Where(i => i.FileTypeID == 5 && !i.Deleted)
.OrderBy(i => i.Rank)
.Select(i => i.FileName)
.FirstOrDefault()

Resources