MySql DB structure with Overriting group settings and allowing settings - mysql

how are you?
I'm working on a project that contains accounts with mailing list.
The account has 3 packages he can buy. Each package has it's own settings. e.g.: first package the user gets 1 email per day, and in second package he gets 5 emails per day.
Another feature that I want is the opertunity to override some of the package settings. Which means, for one account I'll set daily email limit as 7.
One more feature I need in this system is email providers. I want the first package to get emails only from first provider, second package from 2 providers and so on.
So I have a problem designing my DB.
I created table emailSubscriptions which has EmailID and name.
I created table accountsGroup which only contains GroupId and name.
I created table accounts which has AccountID, GroupID (foreign key), Email, password and investment. (According to his investment he gets his package).
I've created table accountsSubscriptions which has SUBSCRIPTION ID, AccountID, EmailID and IsActive.
I created table packages which contains PackageID, GroupID, from investment and to investment, and all other package settings e.g. maxEmailsPerDay ....
Of course the end user has. GUI that he can see his settings and edit what he can according to his current package. The admin of the users has GUI too.
Any way, now I got stuck.
I thought about adding to accounts all package columns and then when I want to send emails, I'll take the settings from the group and where ever it's not 0 / empty just override, but the problem is when some settings are 0 / 1, then the column is default 0 and if the groupSettings is 1 for something and I want to turn it off I can't. So this is the first problem
The second problem is with allowed emails subscriptions ... Same problem actually.
I thought about adding to package the allowedEmails, but then it means when ever I send the emails I need to use LIKE operator - and this is not good for runtime.
So I really need you help... Hope you can help me.
Thanks !!

The requirements part lacks clarity, I'd say.
But let's go for it anyway.
Let's extract entities from this messy field of things.
Each entity would generally means one table.
Start from Account.
Account has Subscriptions. It is not clear what's the relation here: if it is 1:1 ("account can have only one subscription") - then reference to it is a part of the Account entity, if it is 1:n - then you'll need a special Account-Subscriptions relation table.
Now Subscription - it is defined by SubscriptionType, or Package, so there must be a table that contains these records (these limits and whatever else you want). Account or Account-Subscription table would refer to it to define what subscription(s) the Account have.
Then Providers - they're referred by SubscriptionType/Packages. If there could be more than 1 Provider per Package/SubscriptionType - then you need additional Package-Provider realtion table.
And finally, the Overrides. That's a trickier part because of the weak requirements on it, but as soon as they're overriding the Package paremeters, I suggest to keep the entity structure same to the package.
You may even place it into the same Package table, sorting 'em out by date, or assign them weights, always keeping the default Package record with the lowest weight.
Then, when you create an override, you copy the whole default record except for the overridden fields, and assign it next weight (or current date), and when you query it - group it and get the MAX().
There's no Email entity itself - but you didn't mention it in your requirements sections whatsoever.
So, that's pretty much it: Accounts, Subscriptions, (optional) Account-Subscription, Packages, Providers, (optional) Package-Provider, (optional, may be incorporated into Packages) Overrrides.
Works for you?

Related

Grouping with associated variables

i have a table as below:
Account no. Login Name Numbering
1234 rty234 1
1234 bhoin1 1
3456 rty234 2
3456 0hudp 2
9876 cfrdk 3
From the table above, you can see that rty234 and bhoin1 registered a same account no of 1234, thus i know that rty234 and bhoin1 are related and i numbered them as 1. The numbering field was based on the account no.
Then I found that rty234 also registered another account no of 3456 and the same account no was registered by 0hudp as well. Thus, i concluded that rty234, bhoin1 and 0hudp are related. Therefore, i wanted to renumber the third and forth row to 1. If they are not further related, then just remain the numbering. How can i achieve that using mysql.
The expected output will be as follow:
Account no. Login Name Numbering New_Numbering
1234 rty234 1 1
1234 bhoin1 1 1
3456 rty234 2 1
3456 0hudp 2 1
9876 cfrdk 3 3
You need to understand how to design a relational database.
These groupings that you want to make with the New_Numbering field should be done at the time the accounts are registered. I see two pieces of arbitrary information that needs to be tracked: account number and login name. Seems like the people registering the account can type whatever they want here, effectively, perhaps account numbers must be numerical. That detail doesn't matter.
What you want here is one account which can have multiple account numbers associated with it, and multiple logins. I would also assume that future development may add more to this, for example - why do people need multiple logins? Maybe different people are using them, or different applications. Presumably, we could collect additional information about the login names that stores additional details about each login. The same could be said about account numbers - certainly they contain more detail than just an account number.
First, you need one main login table.
You describe rty234 and bhoin1 as if they are unique people. So make this is a login_name column which is a unique index in a login table. This table should have an auto-increment login_id as the primary key. Probably this table also has a password field and additional information about that person.
Second, create an account table.
After creating their login, make them register an account with that login. Make this a two-step process. When they offer a new account number, create a record for it in the account table with additional identifying information that only the account-holder would know. Somehow you have to validate that this is actually their account in order to create this record, I would think. This table would also contain an auto-incremented primary key called account_id in addition to account_no and probably other details about the account.
Third, create a login_account table.
Once you validate that a login actually should have access to an account, create a record here. This should contain a login_id and an account_id which connects these two tables. Additionally, it might be good to include the information provided which shows that this login should have access to this account.
Now, when you want to query this data, you can find groups of data that have the same login_id or account_id, or even that share either a login or an account with a specific registration. Beyond that, it gets hairy to do in an SQL query. So if you really want to be able to go through the data and see who is in the same organization or something, because they share either a login or an account with the same group, you have to have some sort of script.
Create an organization table.
This table should contain an organization_id so you can track it, but probably once you identify the group you'll want to add a name or additional notes, or link it to additional functionality. You can then also add this organization_id field to the login or account tables, so you can fill them once you know the organization. You have to think about if it's possible for two organizations to share accounts, and maybe there's a more complicated design necessary. But I'm going to keep it simple here.
Your script should load up all of the login_id and account_id values and cache them somewhere. Then go through them all and if they have an organization_id, put their login_id or account_id in a hashmap with the value as the organization_id. Then load up all of the login_account records. If either the login_id or account_id has an organization_id in its hashmap, then add the other to its hashmap with the same organization_id. (if there's already one there, it would violate the simple organization uniqueness assumption I made, but this is where you would handle complexity - so I would just throw an exception and see if it happens when I run the script)
Hopefully this is enough example to get you started. When you properly design a database like this, you allow the information to connect naturally. This makes column additions and future updates much easier. Good luck!

Workforce Management database design

Good evening,
I write you after days of "thinking": D
I'm working on a WFM system that allows you to manage activities from the field.
But now the request to manage several different activities forced me to redesign the whole DB.
Originally only 2 types of activities were handled (Installation, Failures) and all was managed by a single database table with all the columns of one and the other activity. The unused column for a task assumed the null value and was not shown via PHP.
Now I have to understand how to structure a db that has the following characteristics:
- the user can configure endless types of different activities (Installation, Failure, Gardening, Reclamation, etc ...)
- the user can configure infinite properties / attributes (Client name, Surname, Address, Expiration date, etc ...)
- for each activity can be associated many properties (certainly not all)
- each property plus being associated with many activities (certainly not all)
- each property can take as many values ​​as it is applied (N ° values ​​= property X activity to which it is applied)
- the user does not have to choose the table in which to insert the property, whether this is called "Customer cousin name" or "IBAN for payment"
Making a practical example I can have that the properties of customer registry are used for each activity, but maybe the property "Height grass" is used only for the activity "Gardening"
Can someone help me? Thank you

Dynamically Customizable Group-Based Authorization in Rails

Currently, in my app there are just 3 roles visitors can have:
admin that has all privileges
user that can can perform several actions about him/her-self within the system
guest that can just watch and send bug reports
Everything is primitively implemented, as follows: in a DB each user has a field where his being admin (stands for 2 in the field) or user (1) is indicated, and in the application_controller.rb it is just checked if logged_in? && current_user.DB_FIELD == 2 (or > 0), and in the necessary controller there occurs a before_filter check, etc.
However, such a simple implementation worked great till recently when we decided to extend the functionality of the system, that is, partly, to allow admin to join users into groups, but there are some moments. For better understanging of what I am going to ask, let me describe the situation from the way I see it (maybe you can suggest something much better and logical):
I am an admin. I open /groups, and see a list of groups.
What is a group? A group, on the one hand, is a set of permissions, and on the other hand, is a combination of users that should have the same permissions within my app.
What is a permission? A permission is one action that each user of the group it assigned to can perform.
I want to unite new users in one group, but this group doesn't exist. So I click the button (which stands for /groups/new), and the Create Group window pops up. There, I have a textfield for a group name, a bulk of checkboxes, each stands for a permission, a field for adding users, and a Save button. I write the group name, check all the permissions I want to assign to this group, add users to this group (I am going to implement this through ajax search: starting typing a user's name, he/she appears, click Enter, and one user is added, then repeat these actions if needed - is it an OK approach?), and click Save.
Ok, I got a new group with several users. But stop, I realized I forgot to add one more person! I return to the Edit Group window (/groups/edit), and refill the misfilled fields. Click Save - and again some magic (I mean, update operations over the DB).
And so, what I have at the final stage? I can freely c/r/u/d the groups, managing users and permissions in them, and perform it in a very GUI-driven way (I mean, checkboxes, ajax search field, etc.)
For two weeks I have been googling/stackoverflowing/scrutinizing info about rails role- and group-based authorizations; have found a lot of solutions like cancan, easy_roles, troles, etc. gems, but cannot find in any of them how to implement a group-based approach, which is dynamic (or customizable? or dynamically customizable?). The only thing that really 100% suits my needs is a redmine permission and permission group approach, but it is overcomplicated due to its over9000-functionality, so I couldn't even fully understand how it is implemented, let alone implement it on my own.
And the questions are (assuming that the set of permissions is permanent so can be hardcoded, and the set of groups is absolutely free; also, if the user doesn't belong to any group he/she has default user permissions; moreover, permissions are not just for c/r/u/d operations, but also for the manually created methods):
What is the best way to implement the above mentioned system? Any existing yet not found by me gem or approach?
How to painlessly-for-scalability store the permissions and the permission groups? A bitmask, or separate permission, permission-to-group assignment, and group tables?
How to painlessly put users into groups? A group field in the user's DB row, or a separate user-to-group assignment table?
Preferably, that the permissions assigned to the group the user being added to, instantly, without any user relogins, apply to him.
Thank you in advanced!
Through several nights I finally came to a solution, which is, to my mind, rather easy yet powerful, but obviously not the best (but still an) implementation.
So, we have now +1 tables, which is of groups, where the columns are id, name, and permission. The last column is a usual integer which represents all the permissions in a decimal number.
The permissions are "aliased" in the controller: e.g. 1 stands for can_manage_smth, 2 stands for can_view_smth, etc.
The permission choice panel is in the /groups section, and is a simple set of checkboxes, applying an onchange action to each we ajaxly perform an OR operation with the permission stored in the table (e.g. we select 3 checkboxes standing for the values of 1, 8, and 16, then we get in our table 25, which is, in turn, a result of 1 | 8 | 16).
So answering my questions:
Not the best but still a solution.
It almost does not affect the scalability because adding a new permission (which is a very rare action) will just demand a new alias of the permission and its before_filter checkings in the beginning of the controller. And I used a bitmask but not as a binary but just a usual decimal value with which simple binary logic operands can play.
No separate user-to-group assignment tables, just a single group_id column in a user table (which already existed).
Hope everything implemented will work perfectly. If any issues occur, I will indicate here. Also, if any new implementation ideas come.
Anyway, thanks to everybody!

Access: Entering multiple subform values with one entry in the form

I've been using Access to create simple databases for a while with great success, but have run into a problem I can't find an answer to.
We ship individualized serialized units to various end-users, and occasionally to resellers that stock them for end-users. I must keep track of which serial numbers end up with each end-users.
The first database I created to handle this recorded company information in one table using their account number as primary key, order information in a second table using the order number as the primary key and linked via the company name, and unit information in a third table with the serial number as the primary key and linked via the order number.
This worked very well until I had to account for these stock orders with a reseller. As it was structured, every unit was linked to one company via the sales order. The issue is that I may ship 20 units on one order to Company A, who then sells 5 to Company B and 3 to Company C.
I realized I needed to link the company name directly to the units, not the orders and have fixed that.
My issue now is simplicity in entering information in the form. My previous database involved the employee in our shipping department merely entering the sales order, selecting the customer name from a drop down menu, then scanning the serial numbers in a subform. This was to ensure simplicity and try to eliminate human error. He had only three things to input, and most of the input was done by scanning barcodes.
As it is currently structured now, the employees out in shipping would have to populate the company name for every record in the subform with the serial number and that complicates things in a way that is unacceptable. At the point of shipping, the company name will always be the same for every unit in the subform.
So.
How would I go about creating a form where the company name is entered once in the form, and automatically populates itself for every record in the subform? The caveat here is that I must also be able to go back occasionally and change the company name of individual units in an order without necessarily affecting the rest of the order. I suppose it starts out as a one-to-many relationship that then must be able to change.
I hope that makes sense.
I have looked for answers using various approaches with auto-fill and relationships and not preserving data integrity, but I feel the answer is just beyond my reach.
The only solution I can think of is to create another field in the unit table for the end-user, and perhaps write a formula that sets this default value as the company name from the order that shipped it. This seems unnecessarily complicated and redundant, there has to be a better way.

mysql database concept - how to avoid duplicate registrations in a global/local setting

a conceptual question:
I have a global system which sales agents use to write orders for clients
Agents can register a client locally (within their own instance of the system)
a client can register himself globally
Agents have access to clients based on client-ID and zipcode
Condition:
I cannot have duplicate clients in the system.
Therefore I need to check during registration, if a client already exists.
I can only make a check on zipcode, because client-ID is an instance-based identifier (a client may have ID-123 in instance A and ID-456 in instance B).
Problem:
Is there a way around showing existing clients with exactly matching zipcode to whoever makes a registration since I don't really want to display something like:
please select one of the following:
Zip 12345 - City: Bigcity - Company Name: some corp.
Zip 12345 - City: Bigcity - Company Name: some other corp.
Zip 12345 - City: Bigcity - Company Name: small ltd.
or create new account
to whoever tries to register.
I cannot modify the global/local structure of the system, but I could add elements or identifiers if this helps.
I hope this is enough info to give some input. Let me know if you need more.
Thanks!
If you don't want to show this dialog for confidentiality reasons, then there is little you can do. The input data just doesn't allow to make any hard decisions programmatically. There could be a typo or something, so I wouldn't trust a program to tinker this together for me. I think the only thing you could do is putting new registrations on a shelf, and only add them to the global database, when they have been confirmed as non-duplicate. You could run a process once per hour that does this.
Find all new registrations within the last hour.
For each registration: find possible duplicate in the existing database.
If duplicate exists: notify manager to handle this manually.
If no duplicate exists: confirm the registration, add it to the database.
You could also write a small tool for the person responsible for handing duplicates, that merges the new registration with an existing client and does whatever is required in that case (e.g. notify the person who did the registration, sending the new client-id, etc).