Neptune – web based lead management / tracking tool – launch

Neptune has been launched and can be found online at the following website address …

www.neptuneleadtracker.com

Neptune has had a “soft” launch in that no huge marketing efforts have been done yet and there are still plenty of features to add to Neptune over the course of time. Marketing and feature development will be on-going.

Any updates to Neptune going forward will be posted at this blog as usual.

Neptune – web based lead management / tracking tool – email address conflict

Last week I spoke about the upgrade to Neptune in that Neptune now accommodates multiple users per account. Originally a Neptune user-account was the whole account. With the advent of the modifications last week a user-account now has a one to many relationship with an account thus allowing for multiple user-accounts under a single account.

Visit Neptune here …

www.neptuneleadtracker.com

I thought this was suitable for purpose until I started thinking into some of the scenarios that could crop up when Neptune finally goes live. If Neptune was left with this solution then the user-account could not be shared across different accounts. Lets say a person from Account A wants to add Jon Doe to his account and a person from Account B also wants to add Jon Doe to his account. This scenario would not be possible without Jon Doe having 2 different accounts with different emails addresses meaning Jon Doe would have to create another email address to have an account with Account B …

Account A
User-account A – Jon Doe

Account B
User-account B – Jon Doe

User-account A and user-account B both would have different email addresses. User-account A and user-account B are represented as 2 distinct user-accounts.

The above system could be improved upon so I set upon improving it. I came up with 2 solutions …

Solution 1

Keep the one to many data structure between the account and users and have it so “email addresses” do not have to be unique in the users table. The email addresses would then only have to be unique per account they are related to. I could then give each account a special login URL which is unique to the account in which the user-accounts can login with. This would result as follows …

Account A
User-account A – Jon Doe

Account B
User-account B – Jon Doe

Although it looks the same as before, user-account A can have the same email address as user-account B, in the old model this was not so and user-account A had to have a different email address to user-account B. User-account A and user-account B are still represented as distinct user-accounts though. The system would know which account the user was attempting to access via the special login URL given to each account and the system would only have to check the uniqueness of the email addresses for each given account.

Solution 2

Get rid of the one to many data structure and replace with a many to many data structure. This solution is the most taxing in terms of implementation as the code would have to be altered in the system to accommodate the many to many relationship which also means swapping a few other database columns round and getting rid of some as they would be no longer needed.

Luckily due to the way the system was abstracted in the code, it turned out that most of the changes could be accomplished by altering a few class methods. Essentially just changing the way those methods returned the data they where fetching from the database.

Using this solution the result now looks like the following …

Account A
User-account A – Jon Doe

Account B
User-account A – Jon Doe

In this solution both accounts share the same user-account. The user-account obviously uses the same email address as it is the same user-account across both accounts. If a fictitious Account C wants to add Jon Doe to their account the system would first check if the email address for Jon Doe exists, if it does then the system will link the Jon Doe user-account to Account C, if not, then the system will create a new user-account for Jon Doe and then link the newly created user-account to Account C.

When a user logs into the system using this solution and the user belongs to more than 1 account the system will present a list of accounts that the user-account belongs to in a selection list. The user can then choose which account to fully log into. If the user-account is only in 1 account then the user is taken straight to the account.

In the end Solution 2 was chosen in favor over Solution 1.

Neptune – web based lead management / tracking tool – multiple users

Neptune – Lead Tracker has been updated. The latest change to Neptune is the multi user capability. Originally Neptune had just 1 account per user. All users would login to the same account using the same username and password. There was no way to differentiate between users within an account.

The fundamental structure of the user accounts on Neptune within Neptune has changed. Now users create an account and an account can have multiple users within it. Each account has a Administration user which controls the creation, updating and deletion of users within the account.

Visit Neptune here …

www.neptuneleadtracker.com

Users are managed within the Administration screen only accessible to the Administration user …

Neptune user accounts page

This change to Neptune is part of a series of changes leading to a paid version of Neptune. It was decided to make Neptune a paid for product using a monthly subscription model.

This release is expected to go live with the new subscription payment integration within the next couple of weeks.

array_map plus other possibilities

When building web applications certain patterns appear in our code. A pattern that use to appear in my code quite regularly is shown in the example below …

Essentially we have an array of data and we want to create a new array out of only part of the original data. The above code can be abstracted using the PHP array_map function as shown in the example below …

PHP includes a number of these functions within its library. PHP also gives you the ability to create your own. The above array_map function can be created in PHP as follows …

Using code similar to the above is also the key to implementing iteration functions on collections allowing you to write code as such …

Or filtering …

The possibilities this opens are numerous. If you would like to know more about writing code similar to the above then I can recommend the following book …

https://adamwathan.me/refactoring-to-collections/

Refactoring to Collections – The Definitive Guide to Curing the Common Loop by Adam Wathan

Neptune – web based lead management / tracking tool – lead statistics update

Neptune – Lead Tracker has been updated. After using Neptune to keep track of my own leads I decided that Neptune needs a way to show how many leads are in each of the lead categories.

Using Neptune you can store, process, search your leads and opportunities.

Visit Neptune here …

www.neptuneleadtracker.com

Originally I was going to leave this feature until I had extensive time to do a nice reporting system for the leads with charts etc. I do not have time to create the reporting system yet so I decided to just put the statistics in the drop-down filter for the lead categories for now.

When selecting the drop-down to the right of the leads data-grid table you will now see the drop-down includes the number of leads in each category …

This is a nice little place to put those statistics for the time being.

Neptune – web based lead management / tracking tool is released

Neptune – Lead Tracker has now officially been released. Using Neptune you can store, process, search your leads and opportunities.

Visit Neptune here …

www.neptuneleadtracker.com

Just enter your details on the homepage sign up form and you will be signed straight into Neptune, a password will be emailed to you so you can access Neptune using your email and password in future sessions.

Update: The sign up process may have changed since the time of this article.

Tips for freelancers

Here are my tips for new or existing freelancers. Looking around the web there are many articles that discuss this theme and they all seem rather identical to each other.

I personally get bored of reading these after a while but I can promise you that even though some of the ideas discussed in this article may be similar to other articles, they are all my personal tips. Each one of these tips is important even if they may seem generic …

Shared office space

Certain situations may happen whilst freelancing when you need the advice of other freelancers. Preferably this would be face to face advice. When working in a shared environment with other freelancers this gives you the opportunity to get the needed advice right at the time you need it.

You may think that having your own private office is better as it avoids interactions with others but this can be a lonely road and getting advice on internet forums or through Skype just does not have the same effect.

Also being around other freelancers can provide a motivational boost to your energy levels as well as providing opportunities you may have missed whilst working in a private office.

Sell yourself as an individual

If you are freelancer then sell yourself as a freelancer. At a certain point in time a client is going to know that you are individual and not a group of people anyway.

A client will wonder where the rest of the company is, at that point you will have to explain that the company consists of just yourself. Save yourself the hassle and just sell yourself as a freelancer.

Payment schedule

Agree to a payment schedule with your clients and stick to it. Preferably agree a payment schedule where you are always paid in advance so you are never having to do work that you have not already been paid for.

Hourly rates

Charge hourly rates for your work. Quoting for fixed price is always a headache.

Even if you think you have everything covered in your fixed price contract the requirements of the contract can be too subjective and no matter how detailed it appears some of the requirements will always be left open to interpretation i.e. client wants a new kitchen, you build him the kitchen, client actually wants a kitchen with gold work surfaces.

Yes you can argue that you have provided the kitchen thus fulfilling the requirement however the client will also argue that the gold work surfaces came under the “new kitchen” requirement.

Arguments can then happen, clients may threaten legal action, you are a 1 person freelancer against the larger client company. You can take this risk if you want to or you could just save yourself the hassle and charge hourly.

Sustainable hourly rates

You may find that you will not always have a full schedule of work as a freelancer. There are gaps in the work flow and other expenses that need to be accounted for.

Clients will always know someone who can do it cheaper but the bottom line is it does not matter what Bill or Joe next door charges for their freelancing services. Your hourly rates need to be sustainable.

If you do not have sustainable hourly rates then you will not have a business for very long. This business has got to support you if it does not then it will not last.

There is no point in charging cheaper rates to get work if those rates are not going to sustain your business.

Contracts

Adopting the “hourly rate” idea earlier your contract should be reasonably straightforward, an hour of work done, an hour of work paid.

Charging by the hour takes some of work out of the contracts as you not agreeing to a requirements specification on a feature by feature basis.

Always have a contract though nevertheless, contracts provide help when dealing with client disputes.

Client profiling

Do not just accept any client that wants you to do work for them.

Profile the client …

  1. What are the clients good and bad points?
  2. Does the client value your work or see you as a commodity?
  3. Is the client someone you really want to work with?
  4. Is the client criminally minded?

Come up with a profile of the clients you want to work with and only or at least mostly only work with those types of clients.

Process

Have a clearly defined process for dealing with clients from on-boarding, design, development, testing, delivery and on-going work.

Every freelancer will have a process of some sort but it is important to get the process defined and written down.

The process is good material to present to clients thus helping with marketing activities. The process is important to you as it improves reliability.

Consider these tips if you are a freelancer or are new to freelancing.

Select2 library solution in Yii2 part 4 – retrieving the data

To continue on from the previous article I wrote about saving the Select2 data …

http://www.jamesbarnsley.com/site/2016/11/07/select2-library-solution-in-yii2-part-3-saving-the-data/

I will now talk about how to the retrieve the stored Select2 data so that the data can be displayed on the front-end Select2 field. Following on from the Task / Countries example, place the following “loadSelect2Items” method inside the Master model or Task model if you did not create a Master model …

The code above can be explained as follows …

  1. Line 3 – return the array of Select2 data using the “array_map” function
  2. Line 4 – store the related entity models name into a variable, in this case that would be the Country models name. This uses the Country relationship that was created in “Part 2” of this article series
  3. Line 5 – store the IDs of the related relationship entity model in the return data, in this case that would be the IDs of the Country model records
  4. Line 6 – find all the records for the model / model property in the “select2_data” table, in this case that would be the Task model and “countries” property

The next step is use the “loadSelect2Items” in the Task model to the load the Select2 data into the “countries” property, place the following inside the “afterFind” method of the Task model …

So that concludes the Select2 library solution for Yii2. I have covered the creation of the necessary database table and the read / write methods for reading / writing the data.

After the initial methods have been setup this solution will provide you with a way of easily putting a Select2 field on your forms that allows for many to many relationships between models with just a couple of line of code.

Select2 library solution in Yii2 part 3 – saving the data

To continue from the previous article …

http://www.jamesbarnsley.com/site/2016/10/31/select2-library-solution-in-yii2-part-2-database/

Once the database table has been created the code can now be written to display the Select2 field on the form and save the Select2 data to the database table.

In this article I will demonstrate the Select2 functionality as though we are wanting to add “Tags” to a Task model. When I say “Tags” I mean the standard web term for Tags. Essentially these are words that you can tag to an entity for example a WordPress article that categorizes the WordPress article using the tags allowing a user to search by those words.

When I say Task model, this is a fictional model in a Yii2 application that will allow the user to create and update tasks. For the purposes of this article it is assumed you will create your own Task model along with the controller and views. Create a standard CRUD for tasks possibly giving each task a name and a description.

You will need to create a Tag database table to store the Tag data along with its associated model. Create a database table with “id” field for the primary key and a “name” field to store the Tag name. Create a standard Yii2 model for the Tag table, this model does not need any methods inside it, it is a blank Yii2 model that extends ActiveRecord.

After you have created your task CRUD functionality and the Tag database table with associated model the Select2 functionality can be integrated.

First the field is added to the form using the Kartik Select2 plugin. The plugin can be found here …

http://demos.krajee.com/widget-details/select2

Add the field to the form using code similar to this. Include the plugin in the form …

Add the field to the form …

Create a “tags” property in the Task model, this will be used to store the tags field data on both saving and retrieving …

Now the field is added to the form and you have a property in which to store the array of data which the Select2 library needs in order to function. Next you need to use the “saveSelect2Items” items method as shown below to save the array data in the “tags” property to the database.

The “saveSelect2Items” method can be placed inside the Task model but it would be better in some kind of global area such as a Master model as is it likely that you will want to use the functionality in more than one model / form. I wrote an article on how to create Master models which can be read here …

http://www.jamesbarnsley.com/site/2016/03/14/create-a-master-model-and-controller-in-yii2/

The “saveSelect2Items” method is as follows …

The code above can be explained as follows …

  1. Line 3 – get the class name of the model object in this case that would be the Task model and convert it to lowercase characters
  2. Line 4 – get the class name of the store model object in this case that would be the Tag model and convert it to lowercase characters
  3. Line 5 – get the Select2 array data of the model object in this case that would be the “tags” property in the Task model
  4. Line 7 – if the model object Select2 property is not empty, in this case that would be the “tag” property
  5. Line 9 – get the current stored records in relation to the model and model properties we are using. In this case the Task model, Tag model and “tag” property
  6. Line 11 – loop through the currently stored records
  7. Line 13 – if the related model object ID is not in the model object property array data. In this case that is if the Tag ID is not in the “tag” property array data
  8. Line 15 – set the deleted flag to 1, which indicates deleted
  9. Line 16 – save the record
  10. Line 22 – loop through the array data in the model object property, in this case that is the Task model “tags” property
  11. Line 24 – check to see whether a record already exists in relation to the model and model properties we are using. In this case the Task model, Tag model and “tag” property
  12. Line 26 – if no existing record can be found
  13. Line 28 to 33 – create a new Select2 record and set the properties
  14. Line 35 and 36 – save the new Select2 record but if it does not save then return false
  15. Line 42 – the else part of the original if statement, if there is no array data in the “tags” property
  16. Line 44 – delete all the existing records for the model we are dealing with. In this case that is the Task model

As mentioned in the database article the “saveSelect2Items” method soft deletes the unwanted Select2 records with a little adaptation this could be altered to hard delete the records.

Now that the “saveSelect2Items” has been created you can call it in your Task model by placing the following code in the “beforeSave” method of the Task model …

The first parameter of the “saveSelect2Items” is the property used to store the Select2 array data, the second parameter is the original model that uses the Select2 field on the form in this case that is the Task model. The third parameter is the relation model in this case that is the Tag model.

The code up to this point puts a Select2 field on a form and saves the Select2 data when the form is saved. If you go back to the form the Select2 field will not be populated with the saved data yet as that is covered in the next article which talks about retrieving the Select2 data.