Opencart set Store preferences - opencart

In Opencart we have the following type of products.
Printed Books (hard copies) which will be shipped to customer.
For the same we have Digital Downloads.
We want an option set at the store level whether user wants to see Downloads or Printed Copies.
When the user chooses downloads option, it should display only downloadable products in all the categories.
When user chooses Printed Copies, it should display only printed products in each of the categories.
Any suggestions to achieve this functionality are welcome.
Thanks

"Any suggestions to achieve this functionality"
From my point of view (which may not be optimal) we need:
Permanent storage for the user preference [5 % done]
add a column to the table <DB_PREFIX>customer with a type of INT and a value of 0 if the user is interested in all products, 1 for digital downloads and so on..., if there is a possibility that you will add new preferences later, then it's better to store a serialized version of all the user preferences in a column of type TEXT
A way to retrieve user preference [25 % done]
you can just retrieve it from the database every time you need it, a better way is to keep it in the session at the same way the user data (like address, telephone)in the class User is kept
A way to change the user preference [40 % done]
some check box in the user settings page, it's also preferable (UX wise) that the user preference is shown in the header next to his name and can be edited directly from there
And finally, displaying products based on that preference [100 % done :D]
you will need to change some code in the controller of the category page, best seller module, latest products .... (any module that involves displaying products)
Simple, naive and ugly solution:you will notice that there is a code segment that copies products data to the view data, it looks like
$data['products'][] = array( in OC 2.X and $this->data['products'][] = array( for versions prior to OC 2, a simple if condition here will be enough, just check for the user preference and decide accordingly whether to copy the product to the view data or not
Better solution: filter products based on the user preference from the very beginning in the model functions, add an extra optional parameter to all model functions that retrieves products (don't forget those functions that retrieves products count) that indicates the user preference, check inside model functions if the parameter is set then do you work in the query

Related

Trying to minimize the number of trips to a database voting table

I use django 1.10.1, postgres 9.5 and redis.
I have a table that store users votes and looks like:
==========================
object | user | created_on
==========================
where object and user are foreign keys to the id column of their own tables respectively.
The problem is that in many situations, I have to list many objects in one page. If the user is logged in or authenticated, I have to check for every object whether it was voted or not (and act depending on the result, something like show vote or unvote button). So in my template I have to call such function for every object in the page.
def is_obj_voted(obj_id, usr_id):
return ObjVotes.objects.filter(object_id=obj_id, user_id=usr_id).exists()
Since I may have tens of objects in one page, I found, using django-debug-toolbar, that the database access alone could take more than one second because I access just one row for each query and that happens in a serial way for all objects in the page. To make it worse, I use similar queries from that tables in other pages (i.e. filter using user only or object only).
What I try to achieve and what I think it is the right thing to do is to find a way to access the database just once to fetch all objects voted filtered by some user (maybe when the user logs in in or the at the first page hit requiring such database access), and then filter it further to whatever I want depending on the page needs. Since I use redis and django-cacheops app, can it help me to do that job?
In your case I'd better go with getting an array of object IDs and querying all votes by user's ID and this array, something like:
object_ids = [o.id for o in Object.objects.filter(YOUR CONDITIONS)]
votes = set([v.object_id for v in ObjVotes.objects.filter(object_id__in=object_ids, user_id=usr_id)]
def is_obj_voted(obj_id, votes):
return obj_id in votes
This will make only one additional database query for getting votes by user per page.

Making a Row Read Only in a tabular form based on table value

I have a tabular form which is updated throughout the year and i wanted to prevent users from editing certain rows. Currently the 'row type' is hard coded however I want the application admin to control which 'row types' are readable / write at certain times. My answered question, click here.
Currently a dynamic action is fired which prevents the rows that contain the type 'manager figure' and 'sales_target' being edited.
I have created a table with the three row types against each customer. Each status is set by a number: 0 to 3 (These i will decode into something meaningful for users).
0 - Row with that row type is read only.
1 - Users can enter into the row with that row type.
2 - row is read only with that row type.
3 - row is complete and set to read only.
I have created a new form (new tab) for the admin user to maintain each status.
Currently for Customer 'Big Toy Store' rows should be set as follows:
Manager Figure row should be read only (since set to 2)
Sales should be readable (since set to 0)
Sales target should be writable (since set to 1)
Please can i be pointed in the right direction, ive looked into jquery but struggling to work out how to pass the output of an sql query to it, so it can be used to determine which rows should be read only.
Link:apex.oracle.com
workspace: apps2
user: developer.user
password: DynamicAction
application name: Application 71656 Read only Rows for Tabular Form
I'm not sure that a tabular form is a good format to work out this idea. As you can see, you require quite a bit of javascript to produce the results you want. Not only that, but this is all client side too, and thus there are some security risks to take into account. After all, I could just run some Firebug and disable or revert all things you did, and even change the numbers. Especially with sales figures, which is something you most definitely do want altered by everybody and is also the nature of your question, security is important.
There are more elegant ways here for you to control this, and not in the least to reduce the amount of highly customized javascript code. For example, you could do away with the tabular form, and instead implement a modal popup from an interactive report. Since the modal popup would be an iframe and thus a different page, you can create a form page. On a form page you have a lot more control over what happens to certain elements. You can specify conditions, read-only conditions, or use authorization schemes. All things you can not evidently use in a tabular form.
I'd think you'd do yourself a service by thinking this over again, and explore a different option. How much of a dealbreaker is using a tabular form actually?
You need the user. You need to know what group he belongs to, and then this has to be checked against the different statusses and rows have to be en/disabled. Do you really want this to happen on the client side?
I'm not saying it can't be done in a tabular form and javascript. It can, I'm just really doubting this is the correct approach!

Django admin store dynamic formset added with ajax

I'm currently implementing a solution using django admin, it allows users to define in the db a product, and then custom attributes and details, more details may be aggregated by a common attribute, this allows me to query with ajax a custom view that returns some JSON data to build automagically the form fields that I need directly in the same formset view (manipulating the DOM).
The current DB design follows this schema:
Catalog(name, description, photo)
Product(rel_catalog, name, base_price, photo, manufacturer_email)
ProductDetail(rel_product, rel_attribute, percentage_price, fixed_price)
ProductAttribute(rel_product, name, description)
As you may see I have a catalog, where there can be more products, a lot of details per product, aggregated by attributes. Then I simple show by default the Catalog, then the select with all available products for that catalog, then, choosing the right Product, I obtain the complete form (each row has a label with ProductAttribute.name and a select with related ProductDetail).
All works pretty dam good, but I also need to store this references in the DB when someone completes the form (making an order with choosen products). This forms are displayed as StackedInline (the ModelAdmin is for the Order).
I don't know how many options there may be per product so I was thinking to use this design to track orders:
Order(customer, status, notes, tot_price, inserted_by)
OrderItem(rel_order, catalog, product, unit_price)
But I don't know how to store the dynamic added inputs...
I was thiking to implement OrderItemProperty(rel_orderitem, rel_productdetail, rel_productattribute) to store each single input... but how do I loop over this unknown fields?
Maybe do you suggest a better design?
If you need more code just ask for it and I'll reply with a pastebin link.
Thankyou.
Finally I got a working solution,
I've created a custom view, overriding the default "add/" view, this way I can customize whatever I want to and I can read the POST data handling each validation, putting then the data in the right model.

Django 1.3 - Admin - "Add Entry" button - copy the fields from previous model instance

Can't find how to do this for some reason.
When clicking the "Add_model Entry" button on the Admin page, I want most of the fields to be filled in with the same values the user put into the previous model instance that they created and saved. (I don't care about which users, just about the last (youngest) saved instance of a model).
Use Case: The user will be creating instances of this model in batch mode, for example 10 very similar items, so it would be very helpful if most of the info is prepopulated each time they hit the "Add entry" button. They may do this 3-4 times per day, if that mattered for some reason, and each batch would have significantly different values in the fields from the previous batch, but each instance in the batch would be similar. Hence my thought of prepopulating with the most recently saved values.
Contrived Example:
class person:<br>
name= CharField => (obvious)<br>
interests= CharField => Example (fly, skate, swim)<br>
age_range= CharField => Example (old, middle, young)<br>
batch 1 = people who fly and are old
Jim Smith, Fly, Old
Sara Smith, Fly, Old
Larry Jones, Fly, Old
batch 2 = skaters
Sam Samuelson, Skate, Young
Alfred Bob, Skate, Old
Jon Jon, Skate, Old
There is much similarity in each batch, but batches can be very different. So I would guess I need a copy of the previously saved model with a new id, (there is no Inheritance here to deal with, but there are ForeignKeys). How do I add it to the "Add Entry" button/site?
As a second option, you could also use the Django Admin Save As functionality. This isn't exactly what you're looking for, but it would allow users to go to a previous entry, edit some fields, and then save that as a new object, which would be close to the same effect.
You could create a custom ModelForm for your ModelAdmin that had an __init__ function that would check to see if there was an instance provided (if there is, that would mean that you're editing an existing object rather than creating a new one), and, if not, query for the latest object and then populate the initial dict with the values that you pulled out of that instance.

What's the best way to represent many booleans in a django model?

I have a model which represents the user's display preferences. Just about all of these preferences are boolean values. Instead of having 50 boolean columns, is there a better way to go about this? In the future when I want to add a new item, I don't want to have to add a new column in my database.
If you have that many booleans and are anticipating adding more, you should not be using columns, but entries.
Then when you need to look up "User wants emails", just search for UserPrefs.objects.get(User=user, Preference=Preferences.objects.get(name="wants email")).
User_Table:
User
username
etc
Preferences_Table:
name
description
etc
UserPreferences_Table:
User (FK_User)
Preference (FK_Preferences)
Setting (Boolean)
Depending on your setup, you may be able to omit the Setting field in the UserPreferences table and simply use the existence of an entry for that User/Preference as a True and the lack of one as a False.
You could also use a bitmap. You only need single char field in you database. Somewhere in your app you store a list of preferences, pref1, pref2, pref3 ... and in the bitmap filed you store a sequence of 1's and 0's that correspond to the preferences.
For example 101 means pref1=yes, pref2=no, and pref3=yes and 011 means pref1=no, pref2=yes, and pref3=yes.
You could make this reusable by creating a new model field type for bitmaps.
" In the future when I want to add a new item, I don't want to have to add a new column in my database."
In this case, you'll want to add a row.
You have a table with the domain of possible setting Names. 50 rows.
You have a table of actual settings. User, Setting Name, Setting Value.