Akeneo: Clone a product - akeneo

We need to clone a product in Akeneo 1.4 (only the SKU should change).
I've found a similar questions (1, 2) in the Akeneo forum, but no answer for the most interesting parts:
clone product (PimCatalogProduct)
clone product values list (PimCatalogProductValue) and attributes
...
Should I use ProductPropertyCopier, ProductTemplateBuilder, ... for this?
Do the target attributes already need to exists when using theProductPropertyCopier?
Is there now in Akeneo 1.4 an easier way to clone a product?

Akeneo does not come with a native way to duplicate products but it's a common need and we are aware of this problem we may prioritise it in the future.
The easiest way to duplicate a product is to normalize it and denormalize it right after that:
$normalizedProduct = $this->serializer->normalize($sourceProduct, 'csv');
$duplicatedProduct = $this->serializer->denormalize(
$normalizedProduct,
'Pim\Bundle\CatalogBundle\Model\Product',
'csv',
[
'entity' => new Pim\Bundle\CatalogBundle\Model\Product()
]
);
// You can now modify the product identifier :)
$this->productSaver->save($duplicatedProduct);
Your product is now duplicated and ready to be used !

Related

Woocoommerce variations information in wp_term_relationships

I have issue with variation display on my wocommerce version 6.8.0 with wordpress version 6.0.1.
I have product A with 2 variations A-1 and A-2.
When I check wp_postmeta where meta_key = 'attribute_pa_size' for both variations I get correct respond from DB.
If I check product on front page I don't see variations on product level. I checked wp_term_relationships and found out that parent product has wrong information stored there once I update that the display is ok.
Is there any possible way to extract all parent attributes from wp_term_relationships connected to all variation product from wp_postmeta where meta_key = 'attribute_pa_size'.
Thank you.

How to ensure developers filter by a foreign key in CakePHP

In a legacy project we had issues where if a developer would forget a project_id in the query condition, rows for all projects would be shown - instead of the single project they are meant to see. For example for "Comments":
comments [id, project_id, message ]
If you forget to filter by project_id you would see all projects. This is caught by tests, sometimes not, but I would rather do a prevention - the dev should see straightaway "WRONG/Empty"!
To get around this, the product manager is insisting on separate tables for comments, like this:
project1_comments [id,message]
project2_comments [id,message]
Here if you forgot the project/table name, if something were to still pass tests and got deployed, you would get nothing or an error.
However the difficulty is then with associated tables. Example "Files" linked to "Comments":
files [ id, comment_id, path ]
3, 1, files/foo/bar
project1_comments
id | message
1 | Hello World
project2_comments
id | message
1 | Bye World
This then turns into a database per project, which seems overkill.
Another possibility, how to add a Behaviour on the Comments model to ensure any find/select query does include the foreign key, eg - project_id?
Many thanks in advance.
In a legacy project we had issues where if a developer would forget a project_id in the query condition
CakePHP generates the join conditions based upon associations you define for the tables. They are automatic when you use contains and it's unlikely a developer would make such a mistake with CakePHP.
To get around this, the product manager is insisting on separate tables for comments, like this:
Don't do it. Seems like a really bad idea to me.
Another possibility, how to add a Behaviour on the Comments model to ensure any find/select query does include the foreign key, eg - project_id?
The easiest solution is to just forbid all direct queries on the Comments table.
class Comments extends Table {
public function find($type = 'all', $options = [])
{
throw new \Cake\Network\Exception\ForbiddenException('Comments can not be used directly');
}
}
Afterwards only Comments read via an association will be allowed (associations always have valid join conditions), but think twice before doing this as I don't see any benefits in such a restriction.
You can't easily restrict direct queries on Comments to only those that contain a product_id in the where clause. The problem is that where clauses are an expression tree, and you'd have to traverse the tree and check all different kinds of expressions. It's a pain.
What I would do is restrict Comments so that product_id has to be passed as an option to the finder.
$records = $Comments->find('all', ['product_id'=>$product_id])->all();
What the above does is pass $product_id as an option to the default findAll method of the table. We can than override that methods and force product_id as a required option for all direct comment queries.
public function findAll(Query $query, array $options)
{
$product_id = Hash::get($options, 'product_id');
if (!$product_id) {
throw new ForbiddenException('product_id is required');
}
return $query->where(['product_id' => $product_id]);
}
I don't see an easy way to do the above via a behavior, because the where clause contains only expressions by the time the behavior is executed.

Fetch field of another Doc in CouchDB?

I'm very new to CouchDB and I have a simple task that I have no been able to find a straight answer.
I have two related docs: order and invoice
invoice = {
id: "invoice_id",
order: "order_id",
values: [...]
}
order = {
id: "order_id",
**order_number: 12345**
}
I have defined a map function that select the unfulfilled invoices, now I need the order_number, which is in the order doc. They are the same transaction. How do I fetch the order_number from the order when I get my invoices?
I've looked around and I'm getting so many answers like: view collation, linked documents, include_docs=true, structure docs to have both...
I'm just looking for the simplest way with a clear explanation. I appreciate any help.
p.s.
Since I'm new I'm finding couchDB development to be very involved. I have map functions, but they need to be pushed to the couchInstance? Or I edit the map functions in Futon? Are there better ways to develop against couchDB? I see there's couchApp but the docs are sparse and the project hasn't been updated in a while.

Instantiate new data on migration

Suppose I have a model Person. Now I create a new model:
class Ranking(models.Model):
person = models.ForeignKey(Person)
score= models.IntegerField(null=False, default= 100)
date_created = models.DateTimeField(auto_now_add=True)
The thing is, I want each Person to have at least one Ranking, so on creation of new Person objects I can just create a new Ranking for each object.
What I don't know is how to create a new default Ranking instance for each of the existing Person objects in the db?
In a django script it would look as simple as something like:
for person in people:
Ranking(person=person).save()
Is there a way to add that code to the south forward migration file? Is there a better way of solving this problem? Any ideas?
First, auto generate the migration python manage.py schemamigration myapp --auto.
Then find something that resembles the following in the migration file (presumably myapp/migrations/00xx_auto__add__ranking.py):
def forwards(self, orm):
# Adding model 'Ranking'
db.create_table(u'myapp_ranking', (
(u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('person', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['myapp.Person'])),
('score', self.gf('django.db.models.fields.IntegerField')(default=100)),
('date_created', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
))
db.send_create_signal(u'myapp', ['Ranking'])
After this, insert something like the following:
# Create 'blank' Ranking entries for all extant Person objects
for person in orm.Person.objects.all():
orm.Ranking.objects.create(person=person)
Other approaches include splitting this into three migrations (this is better say if you have a large dataset in a production environment):
add the model, with the person field not required
add a separate data migration (python manage.py datamigration myapp), and insert into it code to do what I suggested above.
run the two migrations above (allow this to take time if necessary)
change the person field to be once it's all populated, and run this final migration
The South docs have something along these lines. There's also a similar question here that might give insight.

Django "bulk_save" and "bulk_update"

UPDATE: ADDED A BOUNTY. PLEASE PROVIDE AN EXAMPLE AND I WILL ACCEPT THE BEST ANSWER
UPDATE 2: Explicit example now included
Carrying on from the same project, where I asked about bulk_create in a separate thread.
I was wondering if there is a way to essentially "bulk_save" - insert if non-existent or simply update if it already exists.
For example:
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
height = models.DecimalField(blank=True, null=True)
weight = models.DecimalField(blank=True, null=True)
I have a list of dictionaries with key-value pairs for these fields. I would like to filter by name, and then update the height and/or weight as these my players are still growing and conditioning. If there is no easy way to "bulk_save", a bulk update would also be helpful.
Reference: June 8, 2012 - "get_or_create()" patch at django project
Bulk_update reference
I just did a variation of the update_many function listed below I seem to have improved speeds tremendously already.
http://people.iola.dk/olau/python/bulkops.py
UPDATE - apparently DSE2 is also an option.
https://bitbucket.org/weholt/dse2
Will update with speed tests tomorrow.

Resources