Requiring fields depending on address type - sylius

In our project we need to add custom fields to the addresses. That's already done extending Adress Model, but now we need that some fields will be required or not required depending on address type.
For example, field_1 must be filled for shipping address
field_2 must be filled for billing address
field_2 is optional for shipping
field_1 is optional for billing
How could we accomplish this?

This is little tricky but not so hard. You need to use Validation groups from symfony for your model. For every group you will define rules and then validate with group. You can apply group in any step, even after submbit. PLease see few links
https://symfony.com/doc/current/form/validation_groups.html#validation-groups
https://symfony.com/doc/current/validation.html
http://symfony.com/doc/current/form/data_based_validation.html

Related

Why related fields use Write function

_name = "my.table"
building_id = fields.Many2one('building', related='floor_id.building_id', readonly=False)
floor_id = fields.Many2one('building.floor')
A user with the read access to 'building' and 'building.floor' tables, tries to create a record in "my.table" If the user chooses building_id and floor_id together an error occurs. The error says that my user has no access to write 'building.floor' table. My question is: why a related field use the write function, what is the difference between the compute and related in this scenario?
Related fields are very simple computed fields. So simple they can be "implemented" with one parameter on field definition. Odoo has generic methods for those fields. For example a lot of developers don't write inverse methods for computed fields, which inverse the compute method, because the simply don't need it. But without it and without storing the computed field, Odoo sets the field readonly.
Related fields have a generic inverse method. In your case changing building_id when there was already a floor_id chosen, Odoo will write the building_id on that floor_id.building_id, because that's how related fields work (i know that's not the best explanation).
The user obviously has no write/update rights on builiding.floor model and that's why there will be the access error message in the end, because Odoo wants to write the new building on the floor.
Seems to me you want to filter the floors by buildings, but you shouldn't use a related field for that. Just put a domain on floor_id which filters by the chosen building_id:
floor_id = fields.Many2one('building.floor', domain="[('building_id', '=?', building_id)]")
You could also use domain operator =, but =? will show all floors when no building was set yet.

Correcting truncated zip codes in Magento through SQL query

Zip codes with leading zeroes were truncated without the zeroes after a migration from X-Cart to Magento. I'm trying to run a SQL query to add the zeroes back but don't know which table/column to run it against in the database. We use the zip code to determine which shipping services will be available to the customer during checkout. Does anyone know where the shipping address (both default and additional) zip codes are located in the database?
The zip / postal code in magento is an attribute of the customer_address entity.
Look in the table mage_eav_attribute to find what the is attribute id and where it is stored, e.g. execute this query to find out where magento is storing the attribute:
select attribute_id
, backend_type
, attribute_code
from mage_eav_attribute
where attribute_code like '%post%' or attribute_code like '%zip%'
For my implementation, the attribute_id = 29, attribute_code = 'postcode' and backend_type = 'varchar'. The column backend_type will tell you what kind of attribute this is on the backend.
varchar tells me that magento stores this attribute in a table called mage_customer_address_entity_varchar. For you this might be different because it seems to treat it as an integer and truncate leading zeros.
Then I can execute the following sql to get the postcodes. Of course, you'd have to modify the attribute table mage_customer_address_entity_varchar to where your implementation of magento is storing this attribute.
select e.entity_id, a.value atype.attribute_code
from mage_customer_address_entity e
join mage_customer_address_entity_varchar a ON a.entity_id = e.entity_id
join mage_eav_attribute atype ON atype.attribute_id = a.attribute_id
where atype.attribute_code = 'postcode'
Finally, you need this for shipping addresses (and not billing addresses?). Default shipping addresses are attributes of customer, so you'll have to modify my above approach to find which customer attribute table contains that information.
I hope this helps you figure out your solution
Cheers
could it be possible for you to just ignore theses leading 0? since for the logic of the system it doesn't matter and if you have to print it, just get the length of the string and add the leading 0 as a string if you want/need to.
If that doesn't work for you, you will have to look into source code of the module you are using to see wich table the module uses.

OpenERP customers separation

Please I would like to know ho to separate customers in category, since we have two type of customers, the first group should only appear in crm->customers only and vice versa to avoid having a huge list of customers when searching.
My first attempt is to add a tag to different customers to separate them, for example the crm customers have the tag name Mass mailing is it correct to achieve this with tags ?? and my second question how to set default search keyword for example if I click on sales -> customers how to set the default value of search box to for example crmOnly tag thanks.
you can use "domain" where ever you want to have a such a separation.

Restrict Access of A Product based on few criterias

Goal:
Show all products to all users who have access rights to the purchase module.
However besides the above rule show only products who have value 'secfab' in the reference field to the users who created the same product.
Problem:
I tried using access records but my logic to build it is weak and I need help.
Case 1:
[('default_code','!=','secfab'),('created_id','=',user.id)]
If I code this then I only get one record and other records are not shown.
Case 2:
['|',('default_code','!=','secfab'),('created_id','=',user.id)]
If I code this then I only all the records and I am not able to achieve privacy that I wanted.
Any Help will be highly appreciated.
Your second case seems to be correct, except the clause for filtering on the creator looks misspelled. This typo could cause the rule to match all records, because the condition on the non-existing field created_id cannot be verified. Shouldn't it be:
['|', ('default_code', '!=', 'secfab'), ('create_uid', '=', user.id)]
which translates to "show all products that don't have secfab as code, plus all products, that the user created, regardless of their code", and seems to do what you want?
create_uid is one of the 4 fields automatically added by the system to all models that have _log_access set to True, which is the default. This is explained in the OpenERP technical memento and in the special fields documentation.

Update an entity inside an aggregate

I was reading a similar question on SO: How update an entity inside Aggregate, but I'm still not sure how a user interface should interact with entities inside an aggregate.
Let's say I have a User, with a bunch of Addresses. User is the aggregate root, while Address only exists within the aggregate.
On a web inteface, a user can edit his addresses. Basically, what happens is:
The user sees a list of addresses on its web interface
He clicks on an address, and gets redirected to this page: edit-address?user=1&address=2
On this page, he gets a form where he can modify this address.
I we decided to bypass the aggregate root, this would be straightforward:
We would directly load the Address with its Id
We would update it, then save it
Because we want to do it the DDD way, we have different solutions:
Either we ask the User to get this Address by Id:
address = user.getAddress(id);
address.setPostCode("12345");
address.setCity("New York");
em.persist(user);
The problem with this approach is, IMO, that the aggregate root still doesn't have much more control over what's done with the address. It just returns a reference to it, so that's not much different from bypassing the aggregate.
Or we tell the aggregate to update an existing address:
user.updateAddress(id, "12345", "New York");
em.persist(user);
Now the aggregate has control over what's done with this address, and can take any necessary action that goes with updating an address.
Or we treat the Address as a value object, and we don't update our Address, but rather delete it and recreate it:
user.removeAddress(id);
address = new Address();
address.setPostCode("12345");
address.setCity("New York");
user.addAddress(address);
em.persist(user);
This last solution looks elegant, but means that an Address cannot be an Entity. Then, what if it needs to be treated as an entity, for example because another business object within the aggregate has a reference to it?
I'm pretty sure I'm missing something here to correctly understand the aggregate concept and how it's used in real life examples, so please don't hesitate to give your comments!
No, you're not missing anything - in most cases the best option would be number 2 (although I'd call that method changeAddress instead of updateAdress - update seems so not-DDD) and that's regardless whether an address is an Entity or Value Object. With Ubiquitous Language you'd rather say that User changed his address, so that's exactly how you should model it - it's the changeAddress method that gets to decide whether update properties (if Address is an Entity) or assign completely new object (when it's VO).
The following sample code assumes the most common scenario - Address as VO:
public void ChangeAddress(AddressParams addressParams)
{
// here we might include some validation
address = new Address(addressParams);
// here we might include additional actions related with changing address
// for example marking user as required to confirm address before
// next billing
}
What is important in this sample, is that once Address is created, it is considered valid - there can be no invalid Address object in your aggregate. Bare in mind however, that whether you should follow this sample or not depends on your actual domain - there's no one path to follow. This one is the most common one though.
And yes, you should always perform operations on your entities by traversing through aggregate root - the reason for this was given in many answers on SO (for example in this Basic Aggregate Question).
Whether something is an entity or VO depends on the requirements and your domain. Most of the time address is just a Value Object, because there's no difference between two addresses with the same values and addresses tend to not change during their lifetime. But again, that's most of the time and depends on domain you're modeling.
Another example - for most of the domains a Money would be a Value Object - 10$ is 10$, it has no identity besides amount. However if you'd model a domain that deals with money on a level of bills, each bill would have its own identity (expressed with a unique number of some sort) thus it would be an Entity.