As a Shop Owner I want to do bulk updates to my stock levels by uploading CSV files.
Lesson Outcomes
By the end of this lesson you should know how to upload files and how to extract object data from an uploaded file if it was a CSV.
New & Modified App Files
./model/objects/FileUpload.mez
./model/objects/StockUpdate.mez
./web-app/lang/en.lang
./web-app/presenters/StockLevelsUpdate.mez
./web-app/views/StockLevelsUpdate.vxml
File Upload
The Helium platform allows for a file of any extension to be uploaded and saved as a blob data type. This is done with the <fileUpload> widget bound to a blob attribute of an object (which is just how the widget works - you can not bind it directly to a blob primitive).
The first, single header line for column names is required. Column names must match the attribute names as defined in the associated object type. For example, an object instance’s first_name attribute will only be populated from the CSV file if the CSV file has a column with a header that is "first_name". Column headers that don’t match attributes from the associated object type will be ignored.
Any parsing errors will result in the entire transaction being rolled back. Detailed feedback to users in terms of where the parser failed is a work in progress.
Complex attributes are supported. For example the CSV file may contain a column header shop.name. This will automatically populate the name attribute of an object that is associated with the primary object through a simple relationship with the name shop. Simple relationships are one-to-one and many-to-one relationships. Other relationships aren’t supported and will be ignored. The object instance that represents the named relationships will only be created if the value in the column is not null. So if none of the complex attributes access through a specific relationships is set to a non-null value, then that related object won’t be created.
Our comma separated values will correspond to the attributes of the object instance we want to save (or a subset thereof, provided we don't exclude required attributes), in this case a StockUpdate object:
StockUpdate object
persistent object StockUpdate {
string stockName;
int level;
decimal price;
date stocktakeDate;
@ManyToOne
Shop shop via stockUpdates;
@ManyToOne
Stock stock via stockUpdate;
}
Note the presence of the stockNameattribute, seemingly redundant because we already have a Stock link. Since we want the CSV uploader to be able to specify a stock name and not an object record UUID, we need stockName as a string attribute so that we can use it to manually map the record in the CSV to a Stock record.
After uploading the CSV, execute the fromCsv() built-in function available on an object instance.
As before, see the attached source code for the omitted parts, if necessary.
An alternative to using the otherwise redundant stockNameattribute on StockUpdate would have been to use a separate, specialised, non-persistent object on which to execute fromCsv and copy over each value to the object we want to save.
Add a success notification in the form of a Mez:alert() as well to avoid a confusing user experience:
Add Comment