The following description should not be construed as a VirtueMart (hereinafter VM) advertisement. I've never engage in trade, so had to spend some time on study of turnkey solutions for online retailers. From the free products have attracted OpenCart and VM. The final choice fell on the second option for several reasons, one of which is the simplicity of maintenance, as my site powered by Joomla! If possible, look closely at the application code. Install PHP 7 on your local server to investigate VM performance. Perhaps the material in this article will also help you make a final decision on what software to use in your online store.
The VM installation is very simple, so I skip this step and will only add that since the site is multilingual, you need to download and install the corresponding languages support files. The following describes the VM version 3.0.14.
NOTE: after installing all languages, define the default language (for example, English) in the dialogue 'Extensions → Languages' of Joomla!. The root language in VM is English, and because not all internationalization packages are fully translated, you can allow to show message in English, in case of absence of needed translation. In fact, the multilanguage support in VM has nuances in some cases, but more on that later.
Start with dialogue of Configuration (VirtueMart → Configuration), which should allow the installed languages:
At the next step describe the Shop (VirtueMart → Shop). The dialogue is simple, but it should still be noted that the size of the image of your company logo, that will appear on invoices, must be within 200х38 pixels and preferably in the format of 'GIF', though declared and other formats to be supported. It is also desirable to standardize the formats of other images on your website. For example, for photos of products I'll use size 200 x 149, 96 dpi.
Then identify the currencies allowed in the store, and first of all, make the substitution of their names in the dialogue 'Extensions → Languages → Overrides' for both administrative panel and website. Now you need to open 'VirtueMart → Currencies', to find the desired currency and make the following settings:
Notice, that the 'Exchange Rate' must have a value of 0 for the main currency of the store, which will be used when specifying prices for goods. At the same time, this field must be filled in for other currencies:
NOTE: the base currency should remain unchanged throughout the existence of the store. Unused currency can be unpublished or removed:
Now add these currencies in 'VirtueMart → Shop':
As can be seen from the figure, the substitution happened, but remains unchanged when you switch the language (see list above left). In the admin panel it's bearable. But on the side of the website the substitution does not occur at all:
Based on the fact that it will be probably fixed in the future, I decided to work around the problem by simply changing the verbal description of the currency with its 3-character code in the dialog 'VirtueMart → Currencies'. You can also remove unneeded now overrides of 'VM_CURRENCY...', made in the dialog of 'Extensions → Languages → Overrides'. I additionally desided to delete the button 'Change currency' by creating the substitution of module 'mod_virtuemart_currencies' and, modifying code of file 'default.php', which presented in the following figure:
Yellow: code is commented out
Blue: changed the name
Red: added code
NOTE: for more information about creating substitutions, see 'Microdata 'Article' support in Joomla! 3.x'
Now the module 'VM-Currencies Selector' looks on the website like this:
Next, determine the Manufacturers and the Categories to which they belong. In my case, the manufacturer only one:
Now we need to create a root category 'Electronics' and put 'Door Bells' into it. To do this, open the dialog 'Product Categories' and consistently describe for each language supported by the site.
NOTE: the list of languages appears after the first save of each category, as shown in the following screenshot. In the future, the 'Save' button must be pressed to save the category description in each language.
In the end, we'll get this structure:
Lets create a description of product in the category 'Door Bells'. For example, the door bell button:
Now you can create the item Shop in Main Menu Joomla! On my website I usually put the additional modules menu on the right side of the screen. In the case of store here will be a list of categories of goods.
NOTE: in current time VM supports 2 sublevels in the category list.
To not get into a quandary in the future if adding of nesting levels needed, I desided to create a pop-up menu for the dialog Store. For this, we need to specify the menu item type 'External URL' and add the character ' # ' in the field 'Link', to deny page reload in case of its refresh:
Add sub-item 'Electronics' and specify its type as 'VM Category Layout'. Repeat the procedure for all languages to get the next structure:
Thus, we have now the ability to easily add additional levels in the shop menu, and not worry about the above restriction in the module 'List of Categories'.
And finally, let's create module of the type 'VM Category' for each language, where choose a category 'Electronics' as the parent:
Check the result of our work:
In general, we have now a workpiece and looks like can finish this topic to get to the developing of product ASAP. But we are interested not only in sell, but even more in manufacturing. As well as first and second is derived from the interest and satisfaction of our consumer's interests, it is important to lay a strong foundation to support the automation of interaction between the customer and production at all stages. So, let's slow down horses and try at this stage to create any order, or see how it looks in numerous examples, kindly provided by the VM developers. As you will see, useful data for the task in the descriptor of order will be only the SKU and order number. So, let's get back to the picture with the product description and consider closely the 'Product SKU'.
NOTE: there is a perception that it is wrong to describe all properties of the product in the SKU, because it is designed to handle by human. For most shops I can agree with this statement, although its length up to 30 characters in general case is considered valid, which is not short. But in this particular case we are interested in maximum support of automation of own production, but not in resale of products from other manufacturers.
Description of SKU format
First, we consider the alphabet that we will use. In the general case, the operator can switch the keyboard layout when entering information, as well as, for example, may dictate the value of the SKU in a telephone conversation. To reduce the likelihood of errors, it is necessary to restrict the set of valid characters. For example, if only the English shop, we could enable all digits, most special characters, and characters of the Latin alphabet, except for the following:
'I' because like '1'
'O' because like '0'
But since our shop is multilingual, then the restrictions will be harder. Allow all digits and Latin characters, also Cyrillic characters, the outline of which looks like Latin. From the list of special characters allow only the 'minus' ( - ), that will be used to separate groups of characters. Thus, the list of allowed symbols is as follows:
D, F, G, J, L, N, Q, R, S, U, V, W, Z,-,0...9
The field of proposed company activity is limited to the manufacture of electronic products and software, so let's design an appropriate SKU. The format of the code number of any product will consist of a header (HD), and two optional groups of the Independent (IP) and Dependent Parameters (DP), always placed in the following sequence:
HD → IP-DP
The separator between HD and IP is absent, and DP always separated by "-". As the name implies, a group of Independent Parameters can be assigned the functions of the device that do not affect the choices of others. At the same time, the device may contain, for example, mutually exclusive parameters for a particular model, that must be assigned to the group Dependent Parameters.
HD - header has the following structure:
|Product code: 2 digits
||e.g. door bell button: 01|
|Model code: 3 digits
||e.g. model 'Colibry': 001|
|Product type: 1 symbol or digit:
||D - the Electronics Product assembled (e.g. door bell button)
R - Printed circuit Board of the Electronics Product with installed elements
Z - empty Printed circuit Board for Electronics Product
S - Software
Thus, for some Electronics Products we can, if necessary, to allocate the order of spare PCB or software.
NOTE: good practice is the presence in SKU of 2-3 symbol length prefix, representing the name of the manufacturer. For example, in my case, it was possible to define it as 'APO'. But, first, these characters are not allowed in choosen alphabet, and secondly, it is desirable to make SKU of minimal length. Therefore, I do not use the prefix.
IP - group of Independent Parameters for a particular type of product
Let us consider the example of Electronic Products (product type "D" classification), which is always decorated in some case (body):
|Case material: 1 symbol||L – metal
S – plastic
W – wood
|Case color: 1 symbol or digit
||D - white
F - black
R - red
G - green
L – blue
N – orange
Q – grey
V – yellow
|Case shape: 1 symbol or digit||R – rectangle
G – bell
S – heart
DP — group of Dependent Parameters
It is the last part of the SKU's structure and, we also consider the example of Electronic Products 'Button of a Doorbell':
|Separator: 1 symbol||"-"|
|Button's backlight (color): 1 symbol||U – absent
Z – modifiable by software
R - red
G - green
|Sound: 1 symbol||U – absent
Q – piezo-buzzer
D – speaker
Thus, the SKU of 'Doorbell Button' model 'Colibry' with the following characteristics:
- Case Material: Plastic
- Case Color: Red
- Case Shape: Heart
- Backlight: Absent
- Sound: Piezo
will be described by 12 symbols: 01001DSRS-UQ.
Is it possible to make a short article?
It seems to be a very simple product and, suddenly such a long definition. We can try to shorten it, if go to the binary notation, and rewrite all of the above in the following form:
|Product code: 7 bit
|Model code: 10 bit|
|Product type: 2 bits||00 - the Electronics Product assembled (e.g. door bell button)
01 - Printed circuit Board of the Electronics Product with installed elements
10 - empty Printed circuit Board for Electronics Product
11 - Software
|Case material: 2 bits||01 – metall
10 – plastic
11 – wood
|Case color: 3 bits||000 - white
001 - black
010 - red
011 - green
100 – blue
101 – orange
110 – grey
111 – yellow
|Case shape: 2 bits||00 – rectangle
01 – bell
10 – heart
|Delimiter (-)||DO NOT USE IN THIS FORMAT|
|Button's backlight (color): 3 bits||000 – absent
001 – modifiable by software
010 - white
011 - red
100 - green
|Sound: 2 bits||00 – absent
01 – piezo-buzzer
10 – speaker
31 bits total, that can be represented in the form of seven characters modulo 16 (Hex-format), and then SKU of our 'Doorbell Button' model 'Colibry' will look like this: 1004941. Yes, we have reduced the descriptor by 5 characters (one of which is the separator '-' was meaningless). But now consider the other side of this approach:
- This abbreviated version is absolutely not informative for the person
- Hex format include the characters 'A, B, C, E', which we excluded from the alphabet of SKU for our multilingual website. We will have to use the modulo 8, which will give only a numerical representation. It may even seem convenient, but will increase the length of SKU. For our example, SKU will turn into 100044501. I.e., the decrease will be just 3 characters.
- While describing the multivariant products in VM, we have a lot of time to fill in the SKU for each variant, and in the case of bit fields it for sure will lead to numerous errors. Symbolic format is clearly winning here.
- It is likely that we may have to create own queries to the VM database, which will be simpler and easier if you apply a symbolic format.
- To automate the processing of orders we will need to create a specialized software parser to scan the order for errors in SKU, as well as separate the process of product manufacturing by the tasks (select of appropriate components and PCB, search preferred at the moment supplier of microchips, compiling software according to the requirements of the order, etc.). In case of binary format, we will need to create it completely. For symbolic version will be enough, for example, to create a JSON schema of the desired SKU, and process it with a standard parser.
So, finally I chose the first version of the SKU format.
Implementation of SKU support
NOTE: do not rush to repeat the described steps
Let's go back to the previously created descriptor of product 'Button' and do the following:
- Change its name to 'Root Door Bell Button-Colibry', thereby determining the product root, because we may produce a buttons of different types. The phrase 'Root-' especially set at the beginning to find easily all the root descriptors of other products later, by sorting or filtering the list on the field 'Product Name'.
- Create the the Header '01001D' in the SKU field, indicating that it is 'the Product of Electronics' from group 'Door Bell Button', which model identified as 'Colibry'. Thus, we created 2 pairs of 'name — digital ID' (01-Door Bell Button and 001-Colibry) that allows us easily automate the necessary checks during production, and at the same time does not hinder the reading of the information by human.
- Remove the mark from the checkbox 'Published' because this root product does not contains the full descriptor, and there is no sense to publish it or translate to different languages. In the tab 'Product Status' set quantity of goods equal to 0 (the 'In Stock'). Notice, that its 'Product Alias' will also be excluded from the URL, but the price will be included in the calculation of derivative products value. So, here you can specify some constant fraction of the goods price, that will be present in any product derived from this root.
Thus, the parent product description will be as follows:
Now we can create the real descriptors of products, derived from this. In the same dialog, click 'Add a Child Product' and create next descriptor:
Change the values in the 'Product Name' for each language, and also set the checkbox 'Published'. Notice, I assigned a short name of the alias, since the VM automatically adds the suffix '-detail' to it, and it should be taken into account to avoid the length of the URL exceed, and to make alias meaningful. Thus, the relative URL-address of this product descriptor in English will look as follows:
Also I left blank the field, concerning the price of this child product. The fact is that if you'll fill it here, then VM will not add the base value to the total cost, which we specified for the parent product. At the same time, the VM will do it if we will describe custom fields, through which we can flexibly vary the price. As you can see, I also did not fill the field 'Product SKU', because in this case it is not fixed and its content depends on user selection.
So, we need to find a convenient VM's standard features for:
- PRODUCTION to easily describe a variety of options for their products
- BUYER to easily specify own requirements to the goods from the variety offered by our production
Consider again a list of 5 parameters, which values we need to see in SKU and user should be able to control when creating an order of "Door Bell Button":
- Case material: (3 options)
- Case color: (8 options)
- Case shape: (3 options)
- Backlight color: (4 options)
- Sound: (3 options)
The total number of variants is 3 x 8 x 3 x 4 x 3 = 864!
VM offers a convenient way to create multivariant custom field for up to 5 parameters. But, in this particular case it does not suit us, because the quantity of options too large. Time-consuming in terms of implementation seems also creating of hierarchical lists of child products descriptors. After all, we need to create not only descriptors, but also reflect variable dependencies according to the price of the final product, while generating the desired SKU.
Let's separate our parameters into 2 groups:
- Case material
- Case color
- Case shape
- Backlight color
For each IP group we'll create a hidden Custom Fields Group. For example, for "Case Material" it will be like this:
In every such group we'll insert 2 custom fields:
1. visible type of "string" to display a list of choices to the user
2. invisible type of "property" to store the SKU pattern, corresponding to the group
For the DP group we'll create a standard visible multi variant field:
NOTE: the headings of visible groups defined as multilingual replacements, the creation of which was previously described.
The following screenshot shows part of the list of created Custom Fields groups:
We can now create a product descriptor. Press button 'New' in the dialog 'Products' and describe, for example, the button "Colibry":
Please notice the field 'Product SKU'. There are no data about the material, color and shape, but information present about absentee of sound and the backlight in this variant of the button. Save this form (English) and edit for each supported language.
Well, it is time to apply our Custom Fields groups. Open the appropriate tab on the same form and select a group or field from the list, prepared by us previously. I chose the first multi variant field, which allows to describe constraints on the joint use of sound and backlight, though it would be logical to specify it last. The fact is that VM processing multi variant and lists of type "string" in the code in different, and in my opinion somewhat conflicting ways, which in result resets the pointers in all lists of type "string" when the page is refreshed or you change the selector in multi variant field, located on the same page. In case of several lists on page, a user might not catch it and be confused of cart content after the button "Add to cart" pressed. I reported this to VM developers and for now, for this reason, multi variant field placed first in the list with hope that user interacts with fields in the top-down direction. The following example shows a fill of multi variant field:
As you can see, it added two times to support descriptors of sound and backlight. In this case, a list of options is significantly reduced for the particular model (2 for each parameter). Notice, that for each option you specify the price, but not a change to the base price, and the expansion of the field "Product SKU" should be filled in strict accordance with the previously described pattern, and only concerning DP-group.
Next, add elements of IP-groups:
As you can see, this model of product has only one type of Case Material (VM_ED_BODY_PLASTIC) and we could remove its list from GUI. But, because next on the same page may be shown a different type of button, which has an advanced list of materials (plastic, metal, etc.), then in my opinion the difference in the presentation of information can confuse customer. Next we see a description of 3 color options, two of which adding 5 units of value to the final price of the product.
Back to the main. In each such group there is a special field of type "Property", the contents of which is intended to specify the location and human-readable representation of this part in the final pattern of SKU. Thus, for example, "2-D" designates the symbol "D" to material 'VM_ED_BODY_WHITE' in the pattern of the SKU, which must be placed second in the final SKU pattern of this product type.
Open the final list of "Products" on our button type "Colibry" - 4 positions, only:
This is because we defined the following list of options for it:
- Case material: (1 option)
- Case color: (4 options)
- Case shape: (1 option)
- Backlight color: (2 options)
- Sound: (2 options)
The total number of variants is 1 x 4 x 1 x 2 x 2 = 16. But, because the number of products in the list is determined by fields in the multi variant custom group, we'll have only 4. Thus, to support all 864 variants calculated previously, we need to describe a total of 12 products, because:
- Backlight (4 options)
- Sound (3 options)
For the customer, the picture is also not replete with a variety of groups and childs options, which allows him to focus on selecting the desired functions. Of course, the media elements will be present, but not intrusive:
Let's try to place an order:
As you can see, the information sufficient for buyer to verify that all ordered properties confirmed in a verbal form, and in general he does not care of how its SKU looks. For us its exact design is crucial, because we have no employees who would read every order and plan its execution, breaking into subprocesses. Therefore, it is necessary to create a VM code replacement, which will handle described previously fields of type "Property", and automatically modify SKU at the time of ordering accordingly. At first glance, this can be done in the code of component, marked in the following screenshot:
A small digression regarding the rules, which I'm trying to follow in the event of the need for changes in third-party code:
"Code changes or additions should be as short as possible and preferably designed in one solid block (i.e. only be present in one place)"
This allows in the future to avoid situations like shown in the humoresque, where the singer brought own notes to the concert, but they are in such a state that pianist cannot catch variety of marks "play here, but do not play there..."
Sorry, I could not find a suitable place in this component, that matches the specified rule. So, I had to make it in VM's kernel code and because it's not a standard solution, I do not presenting it here. It is made in the form of one short block of code, which eventually allows to properly show the user all information, including SKU:
Unfortunately, VM does not substitutes multilingual definitions when displaying orders in the admin panel, but in this case it is not a big problem:
So, presented approach to the description of the product allows to:
- structure the SKU in a single standard dialog GUI of VM
- easily change the sequence of items in the SKU pattern and their values, regardless of the physical position of lists on the form
- exclude errors in the description of the product, because SKU is automatically filled in at checkout
- combine a large number of lists of various types in the descriptor of the product
- significantly reduce labor costs for description of various options of the product and its meta tags
Email Agent emulation
The VM sends emails to the buyer and seller while order confirmation. Because we are developing on the local server, then at this moment mail error will occur. So, it is necessary to install and configure an appropriate software. In the case of Linux, it is usually 'sendmail'. But for this purpose I use a simple emulator of the unknown programmer, which found in the comments to one of articles on the Internet. Here is its code:
while IFS=read line
echo "$line" >> $name
chmod 666 $name
Place it in a file, for example, under the name of 'fake_sendmail.sh' and save in the directory '/usr/sbin/sendmail', giving it the attribute of 'executable'. Create a directory 'sendmail' as indicated in the variable 'prefix' of code. Specify the path to the file 'sendmail' in 'php.ini':
sendmail_path = /usr/sbin/sendmail/fake_sendmail.sh
Open the tab 'Server' dialog in Joomla! 'Global Configuration', and select 'Sendmail' as a mail agent:
Now email messages will be stored in the directory 'sendmail', and you can look over them by standard means. For example, here is the order shipment confirmation email view in 'Thunderbird Mail':
Tools and documents
|Operating system:||Linux (for example http://www.ubuntu.com/download)|
|Software:||LAMP (for example https://bitnami.com/stack/lamp)
CMS Joomla! (https://www.joomla.org/)
Apache HTTP Server (https://httpd.apache.org/docs/2.4)