My requirement is to show button only if my #order.display_total < $200
so when I have included given code:
- if method.method_type == 'cashondelivery' && #order.display_total < $200
.form-buttons{"data-hook" => "buttons"}
= form.hidden_field :cod_pay, :value => true
= submit_tag "Order Now", :class => 'order-now btn btn-danger'
it gives me error :
NoMethodError - undefined method `<' for #<Spree::Money:0x007ff3d9366490>:
where as #order fetch this:
#<Spree::Order id: 5964, number: "R981938713", item_total: #<BigDecimal:7ff3d2514f78,'0.3843E3',18(18)>, total: #<BigDecimal:7ff3cea3bd20,'0.3843E3',18(18)>, state: "address", adjustment_total: #<BigDecimal:7ff3d25149b0,'0.0',9(18)>, user_id: 1, completed_at: nil, bill_address_id: 24481, ship_address_id: 24482, payment_total: #<BigDecimal:7ff3d25142f8,'0.0',9(18)>, shipping_method_id: nil, shipment_state: nil, payment_state: nil, email: "admin#skinnymint.com", special_instructions: nil, created_at: "2015-12-27 03:45:02", updated_at: "2015-12-28 12:30:34", currency: "USD", last_ip_address: "127.0.0.1", created_by_id: 1, shipment_total: #<BigDecimal:7ff3d251eb68,'0.0',9(18)>, additional_tax_total: #<BigDecimal:7ff3d251ea00,'0.0',9(18)>, promo_total: #<BigDecimal:7ff3d251e7d0,'0.0',9(18)>, channel: "spree", included_tax_total: #<BigDecimal:7ff3d251e5c8,'0.0',9(18)>, item_count: 7, approver_id: nil, approved_at: nil, confirmation_delivered: false, considered_risky: false, guest_token: "aGoCAkyLXJs1oOUp9dS96w", locale: nil, state_lock_version: 0, cod_pay: false>
and #order.display_total = $398.40
Please guide me how to put if condition for this as I am new in spree rails. Thanks in advance.
#order.display_total returns a "money" object that does not have a comparison. However I notice that your object also has an "item_total" field, that appears to have the numeric value. So #order.item_total < 200 will work. However this will not take into account monetary conversion etc.
Your conditional is comparing different types. The less than sign can only be used to compare numbers. You will need to convert #order.display_total to a numeric and remove the dollar sign from the right side of the comparison.
Even better would be to move that logic to a helper method, thereby keeping the view free from logic.
I suggest to compare the amount without '$' I'm not sure how you store the amount so in case you can compare numbers directly it's the easiest solution to use.
Otherwise create a simple method that extract number and compare them:
def is_allowed?(amount,total)
nbr1 = amount[1..-1]
nbr2 = total[1..-1]
amount < total
end
Dont use $. If order.display_total is a string: cast to int/double/float and then try to test it with < 200
Related
I have a FeatureCollection with a column named Dominance which has classified regions into stakeholder dominance. In this case, Dominance contains values as strings; specifically 'Small', 'Medium', 'Large' and 'Others'.
I want to replace these values/strings with 1,2,3 and 4. For that, I use the codes below:
var Shape = ee.FeatureCollection('XYZ')
var Shape_custom = Shape.select(['Dominance'])
var conditional = function(feat) {
return ee.Algorithms.If(feat.get('Dominance').eq('Small'),
feat.set({class: 1}),
feat)
}
var test = Shape_custom.map(conditional)
## This I plan to repeat for all classes
However, I am not able to change the values. The error I am getting is feat.get(...).eq is not a function.
What am I doing wrong here?
The simplest way to do this kind of mapping is using a dictionary. That way you do not need more code for each additional case.
var mapping = ee.Dictionary({
'Small': 1,
'Medium': 2,
'Large': 3,
'Others': 4
});
var mapped = Shape
.select(['Dominance'])
.map(function (feature) {
return feature.set('class', mapping.get(feature.get('Dominance')));
});
https://code.earthengine.google.com/8c58d9d24e6bfeca04e2a92b76d623a2
In F#, assume I have a person record as:
type person =
{ LastName: string option
BirthDate: System.DateTime option }
Now, I want to create a list of 100 persons (this fails. Both name and The System.DateTime(...) is incorrect):
let people = [for a in 1 .. 100
do yield {
LastName= Some "LastName"+a
BirthDate = System.DateTime(2012,11,27)
}]
How is this done?
TIA
There are two separate issues with the code, but your general approach is good!
First, Some "LastName"+a is interpereted as (Some "LastName")+a, which is not the right parenthesization. Also a is an int which cannot be automatically turned into a string, so you need to explicitly convert it. The correct version is Some("LastName" + string a).
Second, System.DateTime(2012,11,27) is DateTime, but you need an option. You can fix this just by adding Some and the right parentheses, i.e. Some(System.DateTime(2012,11,27)).
As a bonus, you can reduce do yield to -> (this is just a syntactic sugar to make this kind of thing shorter). I would write:
open System
let people =
[ for a in 1 .. 100 ->
{ LastName= Some ("LastName"+string a)
BirthDate = Some(DateTime(2012,11,27)) } ]
I'm trying to make sure that a given method is being called when called by a callback.
Basically, I have a RiskMatrix model, that calls 2 private methods on callback after_save
So I'm trying to test that those methods are properly called.
thanks a lot for your help
class RiskMatrix < ActiveRecord::Base
after_save :alert_admin, :save_suspicious_ip, if: proc {score.length >= ALERT_THRESHOLD}
private
def alert_admin
[...]
end
def save_suspicious_ip
[...]
end
end
risk_matrix_spec.rb
describe 'after_save' do
context 'score.length > ALERT_THRESHOLD' do
it 'should run alert_admin' do
matrix = build(:risk_matrix, score: 'ABCD')
expect(matrix).to receive(:alert_admin)
end
it 'should run save_suspicious_ip' do
matrix = create(:risk_matrix, score: 'ABCD')
expect(matrix).to receive(:save_suspicious_ip)
end
end
end
both tests fail
(#<RiskMatrix id: 3201, score: "ABCD", user_id: 3115, created_at: "2019-02-05 16:27:01", updated_at: "2019-02-05 16:27:01">).alert_admin(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
(#<RiskMatrix id: nil, score: "ABCD", user_id: nil, created_at: nil, updated_at: nil>).save_suspicious_ip(*(any args))
expected: 1 time with any arguments
received: 0 times with any arguments
You can use shoulda-callback-matchers to test your callbacks
it { is_expected.to callback(:alert_admin).after(:save) }
The other way to test is verify that after save a matrix a suspicious_ip must exist.
let(:matrix) { create(:risk_matrix, score: 'ABCD') }
context "when score.length > ALERT_THRESHOLD" do
it "after create a matrix" do
expect(matrix.suspicious_ip).to_not be_nil
end
end
context "when score.length < ALERT_THRESHOLD" do
it "after create a matrix" do
expect(matrix.suspicious_ip).to be_nil
end
end
Maybe I am missing something but I am not seeing the save calls, have you tried:
it 'should run alert_admin' do
matrix = build(:risk_matrix, score: 'ABCD')
allow(matrix).to receive(:alert_admin)
matrix.save!
expect(matrix).to have_received(:alert_admin).once
end
Before you save you let RSpec know you gonna stub that method, after the save you verify the method was called.
How can I create a fake with FakeItEasy that allows different return values on successive calls. This is one example of what I would like to be able to do:
var enumerator = A.Fake<IDictionaryEnumerator>();
A.CallTo(() => enumerator.MoveNext()).Returns(true); //Expected value for first call
A.CallTo(() => enumerator.Key).Returns("key1");
A.CallTo(() => enumerator.Value).Returns("value1");
A.CallTo(() => enumerator.MoveNext()).Returns(false); //Expected value for second call
Assert.IsTrue(enumerator.MoveNext()); //Fails
Assert.IsFalse(enumerator.MoveNext());
The assertion will fail since it the last set up of MoveNext will overwrite the first one.
Is it possible to do what I want in FakeItEasy?
.
[Edit]
Clarified the original question's example and provided a working example below.
Based on Patrik's answer this code shows how you can set up the fake. The trick is to reverse all setups and use Once().
var enumerator = A.Fake<IDictionaryEnumerator>();
A.CallTo(() => enumerator.MoveNext()).Returns(false).Once();
A.CallTo(() => enumerator.MoveNext()).Returns(true).NumberOfTimes(2);
A.CallTo(() => enumerator.Key).Returns("key2").Once();
A.CallTo(() => enumerator.Value).Returns("value2").Once();
A.CallTo(() => enumerator.Key).Returns("key1").Once();
A.CallTo(() => enumerator.Value).Returns("value1").Once();
while(enumerator.MoveNext())
{
Debug.WriteLine(enumerator.Key + ": "+ enumerator.Value);
}
This will print:
key1: value1
key2: value2
I'm not entirely sure that I understand what you mean, the code you supplied will always fail. However if you mean that you want it to return true the second time it's called it can be done. There are a couple of different ways that I can think of, two of them are:
A.CallTo(() => enumerator.MoveNext()).ReturnsNextFromSequence(false, true);
The other way is:
A.CallTo(() => enumerator.MoveNext()).Returns(true);
A.CallTo(() => enumerator.MoveNext()).Returns(false).Once();
Edit:
On second though I guess I understand your question better, what you want to happen is that MoveNext should return true the first time and false the second time? If that's the case just change the orders of the values in the examples above.
FakeItEasy does not use a record/replay model and you are correct in that the latest configured rule has precedence over any earlier specified rules. That's why you have to specify repeat - ".Once()" - on the latest configuration for it only to be valid once.
There are many reasons why the latest has precedence, one of the most important ones is that it lets you set up a default return value in the setup of your fixture and override it to return specific values in some of your tests, this is impossible when using a record/replay model.
The OP's example based on Patrik's answer is fine ... but tedious if the sequence grows large. To supplement that answer consider that even though fake/mock examples most often show a bunch of straight line code to Arrange themselves you actually have the full power of a programming language at your command. Conditionals, loops, and even procedures.
So consider the following:
public static void AFakeDictionaryEnumeratorReturns(
IDictionaryEnumerator enumerator, params object[] pairs)
{
if (0 != pairs.Length % 2)
throw new ArgumentException("pairs must have even number of elements", "pairs");
int n = pairs.Length / 2;
A.CallTo(() => enumerator.MoveNext()).Returns(false).Once();
A.CallTo(() => enumerator.MoveNext()).Returns(true).NumberOfTimes(n);
for (int i = pairs.Length; i > 0; i -= 2)
{
A.CallTo(() => enumerator.Key).Returns(pairs[i - 2]).Once();
A.CallTo(() => enumerator.Value).Returns(pairs[i - 1]).Once();
}
}
and now the test becomes:
var enumerator = A.Fake<IDictionaryEnumerator>();
AFakeDictionaryEnumeratorReturns(enumerator,
"key1", "value1", "key2", "value2", "key3", "value3");
var keys = new List<object>();
var values = new List<object>();
while (enumerator.MoveNext())
{
keys.Add(enumerator.Key);
values.Add(enumerator.Value);
}
Assert.Equal(new List<object> { "key1", "key2", "key3" }, keys);
Assert.Equal(new List<object> { "value1", "value2", "value3" }, values);
(An IDictionaryEnumerator deals in pairs, so this example isn't as clearly beneficial as it could be. For a standard IEnumerator<T> a single static generic method would serve for a whole bunch of different enumerators.)
Is it possible to do something like this in SubSonic3?
_db.Update<Product>()
.Set("UnitPrice")
.EqualTo(UnitPrice + 5)
.Where<Product>(x=>x.ProductID==5)
.Execute();
I would need something lik this:
UPDATE Blocks
SET OrderId = OrderId - 1
WHERE ComponentId = 3
But in SubSonic3
I think you can here is a sample for demonstrating how you can use subsonic 3
// One thing you might not have seen with Linq To Sql is the ability to run Updates
//and Inserts, which I've always missed and have now implemented with SubSonic 3.0:
db.Update<Products>().Set(
x => x.Discontinued == false,
x => x.ReorderLevel == 100)
.Where(x=>x.Category==5)
.Execute();
db.Insert.Into<Region>(x => x.RegionID, x => x.RegionDescription)
.Values(6, "Hawaii")
.Execute();
and here a link to the full demonstration
i do it as a select
var model = ClassName.SingleOrDefault(x => x.id == 1);
model.name = "new name";
model.tel = " new telephone;
model.save();
done