Ruby on Rails

Depends how you interpret things

Spree Extend: Updating eligibility criteria for any existing promotion rule

As I mentioned in my last post spree-extend, how to create custom promotion rule(s) while working with Spree based e-Commerece website. Last weekend, I faced a situation where I need to update the existing promotion rule to handle some specific condition.

Scenario:
For example, when I select “Product(s)” spree default rule, it gives us the option to choose products manually or choose by product group and its working as expected. Later, my client told me he wants, when he selects by product_group he can actually select some Taxons/Tags so that only the products belongs to that product_group and has taxon(s) listed there are eligible for this promotion.

Solution:
For updating any existing promotion rules in spree there are few generic steps we need to follow,
Step1. Extend the corresponding spree->promotion->rules model class. Here, I created a file app/models/promotion/rules/product_decorator.rb.

Promotion::Rules::Product.class_eval do
end

Step2. Create the attribute accessors/ accessibles for new attributes you needed.

Promotion::Rules::Product.class_eval do
  has_and_belongs_to_many :taxons, :class_name =>"::taxon", :join_table => "taxons_promotion_rules", :foreign_key=>"promotion_rule_id"
  attr_accessible :taxon_ids_string
  //setter and getter methods
  def taxon_ids_string
    self.taxon_ids.join(",")
  end
  def taxon_ids_string=(string)
    self.taxon_ids = string.split(",").map(&:strip)
  end
end

Step3. update the corresponding View file for the same rule in admin/promotions/rules/_product.html.haml or .erb if you are using erb. Add the required code for handling the same. In My case I added one TokenInput object to get multiple taxons selection. Add code something like this… where-ever you think is more suitable for you.

%p{:class=>"field products_rule_taxons"}
  %label
    = "Choose Taxons"
    = taxon_picker_field "#{param_prefix}[tag_ids_string]", promotion_rule.taxon_ids_string

There are 2 different ways of adding this to view file. One, you can write a decorator and tell before/after which object you want to put this code. Second, you can re-write the complete file and do whatever you need. Upto you.

Also, taxon_picker_field is a helper method which I created for creating the tokenInput/tokenizer object. Create the AdminBaseHelper decorator file, if not exists and put the following code or something like that,

Admin::BaseHelper.module_eval do
  def taxon_picker_field(name, value)
    taxons = value == "" ?  [] : Taxon.where("id in ('#{value}')")
    taxon_names_hash = taxons.inject({}){|memo,item| memo[item.id] = item.name; memo}
    %(tag_picker_initializer();).html_safe
  end
end

Step4. Update the eligible? and/or eligible_products methods as per your rule updations. Here in my case I just need to change the eligible_products method. Add the following code in app/models/promotion/rules/product_decorator.rb

  def eligible_products
    if product_group
      return self.taxons.collect(&:products).flatten
    end
    products
  end

Or something like that as per your requirements

And yes, We are good to go and the new rule criteria will be applied from now on-wards.

Good luck, In case of any query, feel free to ask here or email me at skr.ymca@gmail.com

Spree Extend: Creating Custom Promotion Rule

I’m working on an E-commerce website for sometime now. We are using spree as backbone of the project and customizing where and when its required. Spree is quite good and fully functioning E-commerce Rails engine which give you base to build a e-commerce website quickly and with lesser efforts.
One of the main features of any e-commerce website is Promotions/Coupons. Spree also has a built in spree promotion module which is ready to use with predefined rules and adjustment calculators. Being an ADMIN I can define any new promotion rules i.e. first order, user specific, products specific etc. Also I can define the actions like ALL or ANY. You can have a look on spree_promo module at spree_promo and see how it works.
Spree already provides some 4-5 predefined Promotions Rules on the basis of which every order get cross-checked whether some adjustments has to be done or not. Most of the time these rules/calculators are more than enough in general usage, but sometimes we need few very specific CUSTOM rules to be defined. Here I’m going to explain how easy it is to create new spree promotion rules.
Create Promotion Rule:
step1. create a model file app/models/spree/promotion/rules/my_custom_promotion.rb

  module Spree
    class Promotion::Rules::MyCustomPromotion < PromotionRule
      // required associations or preferences if any
      // required attribute accessible if you need to protect some attributes from 
mass assignment
      // match polices and operators
      MATCH_POLICIES = %w(any all) // as per your requirement

      def eligible?(order, options={})
        // This method is the place where every order is being verified whether its 
eligible for any promotional discount
      end
    end
  end

Step2. Add this custom promotion rule to default spree promotion rules list. Write the following code in either application.rb or some initializer

  initializer "spree.promo.register.promotions.rules" do |app|
    app.config.spree.promotions.rules += [Spree::Promotion::Rules::MyCustomPromotion]
  end

Step3. Add the translations for name & description for custom rule as spree use the standard view for all with Translation method t(‘name’) or t(‘description’). write the following code in your config/locales/en.yml(or any other locale file if you are having multilingual products).

 
  en:
    promotion_rule_types:
      product_by_tag:
        name: Products By MyCustomPromotion
        description: Add products from MyCustomPromotion

Step4. create the view partial file for the custom promotion rule. add a file to app/admin/promotions/rules/_my_custom_promotion.html.erb or haml or something else depending on the template engine you are using for views.

And, restart your application server and you are good to go. Now whenever you are going to edit the Promotion, in the promotions rules list you will see you custom rule also available.

NOTE:: if you want some custom price adjustments/calculations as well, then you have to create a new calculator. E.g. If I want to define some flat percentage benefit on my custom promotion we have to create app/models/spree/calculator/flat_percentage.rb

  module Spree
    class Calculator::FlatPercetange < Calculator
      // preferences if there are any.
      // attributes accessibles
      def compute(object)
        // main method where we have to compute the adjustments we have to made.
      end
    end
  end

I hope it helped someone. In case of any query, please feel free to ask here or drop me a mail at skr.ymca@gmail.com

Titanium : Passing parameters between windows [How to make things global]

While working on any titanium application, one of the common possibilities is to use some variables/constants across the windows. In Titanium, windows use to have their on context. That means the variables/values available on one window are not available on the others linked windows by default. So, if we are required to pass parameters between windows,  there are many different ways to achieve this. So, choosing a perfect approach for passing variables/parameters within windows depends on the requirement we are having. In our last project we had used few different approaches as per our requirements. Few of them are :

Ti.App.Properties:

There are few cases where we need to store values to be used everywhere in the application, and we want to retain those values even when application is not-running/ in-background. The App Properties module is used for storing application related property/value pairs which persist beyond application sessions.

We can set the property/value pair as:

Titanium.App.Properties.setString("my_prop","cool");

Now, as property/value pair is set. Now I can simply retrieve that value where I want in the application as:

var value = Titanium.App.Properties.getString("my_prop");

While setting properties in Ti.App.Properties, we have to make sure few things:
>> we are actually making things globally available, means whatever values we are storing, should not conflict with already existing global titanium constants, otherwise functionality will suffer. For more information, check Titanium documentation at Titanium.App.Properties

Ti.App:

There are cases, when we need few values to be available all over the application, but when we close the application, those values should not be available any-more. For example,  while working on an application I need to access the current locale for the device for different purposes. But when I closes the application, I don’t need that value to persist as use can change the locale in-between as well. So better to make request to get these kind of values when app initializes and persist those values throughout the application session.

We can declare methods and variables to be globally available with Ti.App as:

Ti.App.sample_variable = “xxxxxx”;

Ti.App.sample_function = function(_args){ //your code for the function };

Then we can use this variable/method anywhere in our application. It will be available in the application session.

App Level Global Declaration:

For past weeks I was wondering about what are the best ways of writing titanium javascript code to make it more generic, reusable and more modular. Tweetanium, the sample application build by titanium/appcelerator team to help people, posses a new approach for design/creation of titanium based applications. Approach is to maintain an Application Level NAMESPACE and write each and every single peace of code wither to that namespace or sub-namespaces to that. e.g.

In app.js of your application,

//app.js

//suppose name of my application is sample, so defining the global namespace or placeholder for my application

var sample = {};

Now I can define my UI, models, controllers methods and variables in the corresponding namespace or placeholder to make them more structured. As,

sample.UI = {};

Now if I want to declare any method or variables, I can place them in corresponding files and assign all the methods/ variables to their parent placeholder.

//UI.js

(function(){

sample.UI.xxxx = function(_args){

//write you code you want to use.

};

})();

For knowing more about how to write MVC structure applications with titanium, stay tuned, as I will be back soon with one more blog post for the same

Passing parameters within successive windows:

If we just need to pass parameters/values between 2 successive windows, then it can be done via sending values as a part of window object it self. Like. for example I’m working on a map related stuff and when I click on a button which leads me to the next window which shows some data corresponds to my geolocation position. Then while creating the window element we can pass those values as part of window object itself. As:

## window1.js

………

var button = Ti.UI.createButton({

label: “button1”,

height: “20dp”,

width: “100dp”

});

button.addEventListener(“touchstart”, function(){

var window2 = Ti.UI.createWindow({url:”window2.js”});

window2.sample_value = “xxxxxx”;

Ti.UI.currentTab.open(window2, {animated:true});

});

##windows2.js

var window = Ti.UI.currentWindow;

Ti.API.info(window.sample_value);

//this will return “xxxxxx” as a values;

These are the few ways of passing variables globally which I used till now. For any query Contact me anytime, or reply back.