require 'spec_helper' module Effective::QbRequestSpecHelper # valid attributes for qb requests def valid_request_attributes { :state=>'Processing', :qb_ticket => Effective::QbTicket.new, :order => Effective::Order.new, :request_type=>'OrderItemSynchronization' } end end describe Effective::QbRequest, "Generating Request QbXML" do include Effective::QbRequestSpecHelper before :each do # let's generate an order that the request will need to use. @order = FactoryGirl.create(:purchased_order) @user = @order.user @qb_request = Effective::QbRequest.new(valid_request_attributes) @qb_request.order = @order @qb_request.save! end # safety check before we get crazy it "should be valid" do @qb_request.should be_valid end it "should generate valid qb_xml for the CustomerQuery state" do @qb_request.state = 'CustomerQuery' @qb_request.should be_valid qb_xml = @qb_request.generate_request_xml @doc = Nokogiri::XML(qb_xml) @doc.xpath("//CustomerQueryRq").first["requestID"].should == (@qb_request.id.to_s) @doc.at_xpath("//CustomerQueryRq//FullName").content.should eq(@order.billing_name) end it "should generate valid qb_xml for the CreateCustomer state" do @qb_request.state = 'CreateCustomer' @qb_request.should be_valid qb_xml = @qb_request.generate_request_xml @doc = Nokogiri::XML(qb_xml) @doc.xpath("//CustomerAddRq").first["requestID"].should == (@qb_request.id.to_s) @doc.xpath("//CustomerAddRq//CustomerAdd").present?.should == true @doc.at_xpath("//CustomerAddRq//CustomerAdd//Name").content.should eq(@order.billing_name) @doc.at_xpath("//CustomerAddRq//CustomerAdd//FirstName").content.present?.should eq true @doc.at_xpath("//CustomerAddRq//CustomerAdd//LastName").content.present?.should eq true @doc.xpath("//CustomerAddRq//CustomerAdd//BillAddress").present?.should == true @doc.at_xpath("//CustomerAddRq//CustomerAdd//BillAddress//Addr2").content.should eq(@order.billing_address.address1) @doc.at_xpath("//CustomerAddRq//CustomerAdd//BillAddress//City").content.should eq(@order.billing_address.city) @doc.at_xpath("//CustomerAddRq//CustomerAdd//BillAddress//PostalCode").content.should eq(@order.billing_address.postal_code) @doc.at_xpath("//CustomerAddRq//CustomerAdd//Phone").content.should eq(@user.phone) @doc.at_xpath("//CustomerAddRq//CustomerAdd//Email").content.should eq(@user.email) end it "should generate valid qb_xml for the OrderSync state" do @qb_request.state = 'OrderSync' @qb_request.should be_valid qb_xml = @qb_request.generate_request_xml @doc = Nokogiri::XML(qb_xml) @doc.xpath("//SalesReceiptAddRq").first["requestID"].should == (@qb_request.id.to_s) @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd").present?.should == true @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd//CustomerRef").present?.should == true @doc.at_xpath("//SalesReceiptAddRq//SalesReceiptAdd//CustomerRef//FullName").content.should eq(@order.billing_name) @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd//TxnDate").present?.should == true @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd//Memo").present?.should == true @doc.at_xpath("//SalesReceiptAddRq//SalesReceiptAdd//IsToBePrinted").content.should == 'false' @doc.at_xpath("//SalesReceiptAddRq//SalesReceiptAdd//IsToBeEmailed").content.should == 'false' @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd").present?.should == true @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd//ItemRef").present?.should == true @doc.at_xpath("//SalesReceiptAddRq//SalesReceiptAdd//ItemRef//FullName").content.should eq(@order.order_items.first.qb_item_name) @doc.at_xpath("//SalesReceiptAddRq//SalesReceiptAdd//Desc").content.should eq(@order.order_items.first.title) @doc.at_xpath("//SalesReceiptAddRq//SalesReceiptAdd//Amount").content.to_f.should eq(@order.order_items.first.subtotal / 100.0) @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd//SalesReceiptLineAdd").count.should == @order.order_items.length + 1 @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd//SalesReceiptLineAdd//Desc").count.should == @order.order_items.length + 1 @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd//SalesReceiptLineAdd//Desc").last.content.should eq(EffectiveQbSync.quickbooks_tax_name) @doc.xpath("//SalesReceiptAddRq//SalesReceiptAdd//SalesReceiptLineAdd//Amount").last.content.to_f.should eq(@order.tax / 100.0) end it "should raise an exception if there is no qb_item_name on the order_item" do @qb_request.state = 'OrderSync' allow(@qb_request.order.order_items.first).to receive(:qb_item_name).and_return(nil) # This should raise an error (@qb_request.generate_request_xml rescue :error).should eq :error end it "should raise an exception if there is no attached order to the request" do @qb_request.order = nil Effective::QbRequest::PROCESSING_STATES.each do |state| @qb_request.state = state (@qb_request.generate_request_xml rescue :failed).should eq :failed end end it "handle_response_xml should transition to the CreateCustomer state if passed a 500 status Code" do @qb_request.state = 'CustomerQuery' @qb_request.should be_valid @xml = "" @qb_request.handle_response_xml(@xml) @qb_request.state.should == 'CreateCustomer' end it "handle_response_xml should transition to the OrderSync state if passed a non-500 status Code" do @qb_request.state = 'CustomerQuery' @qb_request.should be_valid @xml = "" @qb_request.handle_response_xml(@xml) @qb_request.state.should == 'OrderSync' end it "should be able to find the first response with a requestID" do @xml = "" Effective::QbRequest.find_first_response_having_a_request_id(@xml).attr('requestID').should eq('500') end it "handle_create_customer_response_xml should return true if passed a valid status code" do customer_response_xml = "" @qb_request.handle_create_customer_response_xml(customer_response_xml).should eq(true) end it "should raise an error if malformed xml is passed" do @customer_response_xml = "" (@qb_request.handle_create_customer_response_xml(@customer_response_xml) rescue :error).should eq :error end end describe Effective::QbRequest do include Effective::QbRequestSpecHelper before(:each) do @qbxml_success = File.read(Rails.root.to_s + '/../fixtures/qbxml_response_success.xml') # let's generate an order that the request will need to use. @order = FactoryGirl.create(:purchased_order) @user = @order.user @qb_request = Effective::QbRequest.new(valid_request_attributes) @qb_request.order = @order @qb_request.save! end it "should be valid" do @qb_request.should be_valid end it "should show an error on missing QbTicket" do @qb_request.qb_ticket = nil @qb_request.save @qb_request.errors[:qb_ticket].present?.should eq true end it "should show an error if request type is OrderItemSynchronization and there is no order" do @qb_request.attributes = valid_request_attributes @qb_request.request_type = 'OrderItemSynchronization' @qb_request.order = nil @qb_request.save @qb_request.errors[:order].present?.should eq true end it "should return Processing when state is empty" do @qb_request.state = nil @qb_request.state.should eq 'Processing' end it "should show an error on an invalid state" do @attributes = valid_request_attributes @attributes[:state] = 'InvalidState' @qb_request.attributes = @attributes @qb_request.save @qb_request.errors[:state].present?.should eq true end it "should return a found record using response qb xml" do allow(Effective::QbRequest).to receive(:find_by_id).and_return(@qb_request) request = Effective::QbRequest.find_using_response_qbxml(@qbxml_success) request.should eql(@qb_request) end it "should return nil if it cannot find the corresponding request using the response qb xml" do response_qbxml = '' allow(Effective::QbRequest).to receive(:find_by_id).and_return(@qb_request) request = Effective::QbRequest.find_using_response_qbxml(response_qbxml) request.should be_nil end end describe Effective::QbRequest, "Working with Synchronizing Orders" do include Effective::QbRequestSpecHelper # we will create an order with five order items attached to it before :each do @qb_machine = Effective::QbMachine.new # let's generate an order that the request will need to use. @order = FactoryGirl.create(:purchased_order) @user = @order.user end it "Order should be valid" do @order.should be_valid end it "test should verify that the order items are attached to the order" do (Effective::Order.first.order_items.size > 1).should eq true end it "should return an empty array if there are no order items to be synchronized" do Effective::Order.delete_all requests = Effective::QbRequest.new_requests_for_unsynced_items requests.should_not be_nil requests.size.should eql(0) end it "should create a request for each order that has no corresponding QbRequest attached to it" do requests = Effective::QbRequest.new_requests_for_unsynced_items requests.size.should eql(1) end it "should not return a request for an OrderItem if its Order has a 'Failed' status" do @order.purchase_state = 'declined' @order.save(validate: false) # return 0 requests because they all belong to the same Failed order Effective::QbRequest.new_requests_for_unsynced_items.size.should eql(0) end it "should not return a request for an Order if a request has already been created for it" do requests = Effective::QbRequest.new_requests_for_unsynced_items request = requests.first # save and persist this request request.qb_ticket = @qb_machine.ticket request.save! request.transition_state('Finished') # This was changed for effective_qb_sync new_requests = Effective::QbRequest.new_requests_for_unsynced_items new_requests.size.should eql(requests.size-1) end it "should return an array of type QbRequest" do Effective::QbRequest.new_requests_for_unsynced_items.each do |req| req.class.should eql(Effective::QbRequest) end end it "should return each request as having a member OrderItem" do Effective::QbRequest.new_requests_for_unsynced_items.each do |req| req.order.should_not be_nil end end it "should return each OrderItem having the correct fields filled in" do Effective::QbRequest.new_requests_for_unsynced_items.each do |req| order_item = req.order.order_items.first order_item.purchasable.kind_of?(Product).should eq true order_item.qb_item_name.should eq 'Product' order_item.price.should eq 1000 order_item.quantity.should eq 1 end end it 'should create one qb_order_item for each order_item' do Effective::QbRequest.new_requests_for_unsynced_items.each do |req| req.qb_ticket = Effective::QbTicket.new() req.transition_to_finished # One QbOrderItem per OrderItem Effective::QbOrderItem.count.should eq req.order.order_items.length Effective::OrderItem.all.each { |oi| oi.qb_order_item.present?.should eq true } end end # it "should not return any OrderItem that has no QuickBooks item name" do # requests = Effective::QbRequest.new_requests_for_unsynced_items # Effective::OrderItem.update_all(:qb_item_name => '') # new_requests = Effective::QbRequest.new_requests_for_unsynced_items # requests.size.should_not eq new_requests.size # end end