Class: Effective::Order

Inherits:
ActiveRecord::Base
  • Object
show all
Defined in:
app/models/effective/order.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(atts = nil, &block) ⇒ Order

Effective::Order.new(items: Product.first) Effective::Order.new(items: [Product.first, Product.second], user: User.first) Effective::Order.new(items: Product.first, user: User.first, billing_address: Effective::Address.new, shipping_address: Effective::Address.new)



300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
# File 'app/models/effective/order.rb', line 300

def initialize(atts = nil, &block)
  super(status: :pending) # Initialize with status pending

  return self unless atts.present?

  if atts.kind_of?(Hash)
    items = Array(atts[:item]) + Array(atts[:items])

    self.user = atts[:user] || items.first.try(:user)

    if (address = atts[:billing_address]).present?
      self.billing_address = address
      self.billing_address.full_name ||= user.to_s.presence
    end

    if (address = atts[:shipping_address]).present?
      self.shipping_address = address
      self.shipping_address.full_name ||= user.to_s.presence
    end

    atts.except(:item, :items, :user, :billing_address, :shipping_address).each do |key, value|
      self.send("#{key}=", value)
    end

    add(items) if items.present?
  else # Attributes are not a Hash
    self.user = atts.user if atts.respond_to?(:user)
    add(atts)
  end

  self
end

Instance Attribute Details

#confirmed_checkoutObject

Set on the Checkout Step 1



43
44
45
# File 'app/models/effective/order.rb', line 43

def confirmed_checkout
  @confirmed_checkout
end

#current_userObject

Set by the checkout controller for non-admin users



40
41
42
# File 'app/models/effective/order.rb', line 40

def current_user
  @current_user
end

#mailer_previewObject

Set by the mailer preview. Disabled delayed payment validations



49
50
51
# File 'app/models/effective/order.rb', line 49

def mailer_preview
  @mailer_preview
end

#send_mark_as_paid_email_to_buyerObject

Set by Admin::Orders#mark_as_paid



47
48
49
# File 'app/models/effective/order.rb', line 47

def send_mark_as_paid_email_to_buyer
  @send_mark_as_paid_email_to_buyer
end

#send_payment_requestObject

Settings in the /admin action forms



46
47
48
# File 'app/models/effective/order.rb', line 46

def send_payment_request
  @send_payment_request
end

#skip_buyer_validationsObject

Set by Admin::Orders#create



48
49
50
# File 'app/models/effective/order.rb', line 48

def skip_buyer_validations
  @skip_buyer_validations
end

#terms_and_conditionsObject

Yes, I agree to the terms and conditions



42
43
44
# File 'app/models/effective/order.rb', line 42

def terms_and_conditions
  @terms_and_conditions
end

Instance Method Details

#add(*items, quantity: 1) ⇒ Object

Items can be an Effective::Cart, an Effective::order, a single acts_as_purchasable, or multiple acts_as_purchasables add(Product.first) => returns an Effective::OrderItem add(Product.first, current_cart) => returns an array of Effective::OrderItems



359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
# File 'app/models/effective/order.rb', line 359

def add(*items, quantity: 1)
  raise 'unable to alter a purchased order' if purchased?
  raise 'unable to alter a declined order' if declined?

  cart_items = items.flatten.flat_map do |item|
    if item.kind_of?(Effective::Cart)
      item.cart_items.to_a
    elsif item.kind_of?(ActsAsPurchasable)
      Effective::CartItem.new(quantity: quantity, purchasable: item)
    elsif item.kind_of?(Effective::Order)
      # Duplicate an existing order
      self.note_to_buyer ||= item.note_to_buyer
      self.note_internal ||= item.note_internal
      self.cc ||= item.cc

      item.order_items.select { |oi| oi.purchasable.kind_of?(Effective::Product) }.map do |oi|
        purchasable = oi.purchasable

        product = Effective::Product.new(name: purchasable.purchasable_name, price: purchasable.price, tax_exempt: purchasable.tax_exempt)

        # Copy over any extended attributes that may have been created
        atts = purchasable.dup.attributes.except('name', 'price', 'tax_exempt', 'purchased_order_id').compact

        atts.each do |k, v|
          next unless product.respond_to?("#{k}=") && product.respond_to?(k)
          product.send("#{k}=", v) if product.send(k).blank?
        end

        Effective::CartItem.new(quantity: oi.quantity, purchasable: product)
      end
    else
      raise 'add() expects one or more acts_as_purchasable objects, or an Effective::Cart'
    end
  end.compact

  # Make sure to reset stored aggregates
  assign_attributes(subtotal: nil, tax_rate: nil, tax: nil, amount_owing: nil, surcharge_percent: nil, surcharge: nil, surcharge_tax: nil, total: nil)

  retval = cart_items.map do |item|
    order_items.build(
      name: item.name,
      quantity: item.quantity,
      price: item.price,
      tax_exempt: (item.tax_exempt || false),
    ).tap { |order_item| order_item.purchasable = item.purchasable }
  end

  retval.size == 1 ? retval.first : retval
end

#amount_owingObject



538
539
540
# File 'app/models/effective/order.rb', line 538

def amount_owing
  self[:amount_owing] || get_amount_owing()
end

#assign_confirmed_if_valid!Object

This lets us skip to the confirmed workflow for an admin…



677
678
679
680
681
682
683
684
685
686
# File 'app/models/effective/order.rb', line 677

def assign_confirmed_if_valid!
  return unless pending?

  assign_attributes(status: :confirmed)
  return true if valid?

  self.errors.clear
  assign_attributes(status: :pending)
  false
end

#confirm!Object

Used to indicate the order has a billing address and is ready for checkout



670
671
672
673
674
# File 'app/models/effective/order.rb', line 670

def confirm!
  return false if purchased?
  return save! if deferred?
  confirmed!
end

#custom_order?Boolean

A custom order is one that was created by an admin We allow custom orders to have their order items updated

Returns:

  • (Boolean)


500
501
502
# File 'app/models/effective/order.rb', line 500

def custom_order?
  order_items.all? { |oi| oi.purchasable_type == 'Effective::Product' }
end

#decline!(payment: 'none', provider: 'none', card: 'none', validate: true, email: false) ⇒ Object

We only turn on the email when done by a delayed payment or from a rake script.



840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
# File 'app/models/effective/order.rb', line 840

def decline!(payment: 'none', provider: 'none', card: 'none', validate: true, email: false)
  return false if declined?
  raise('order already purchased') if purchased?

  assign_attributes(
    skip_buyer_validations: true,

    status: :declined,
    purchased_at: nil,
    purchased_by: nil,

    payment: payment_to_h(payment),
    payment_provider: provider,
    payment_card: (card.presence || 'none')
  )

  if current_user&.email.present?
    assign_attributes(email: current_user.email)
  end

  error = nil

  Effective::Order.transaction do
    begin
      run_purchasable_callbacks(:before_decline)
      save!(validate: validate)
      run_purchasable_callbacks(:after_decline)
    rescue => e
      self.status = status_was
      error = e.message
    end
  end

  raise "Failed to decline order: #{error || errors.full_messages.to_sentence}" unless error.nil?

  send_order_emails! if email

  true
end

#declined_reasonObject



880
881
882
883
884
# File 'app/models/effective/order.rb', line 880

def declined_reason
  return unless declined?

  delayed_payment_purchase_result.presence || 'credit card declined'
end

#defer!(provider: 'none', email: true, validate: true) ⇒ Object



795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
# File 'app/models/effective/order.rb', line 795

def defer!(provider: 'none', email: true, validate: true)
  raise('order already purchased') if purchased?

  # Assign attributes
  assign_attributes(
    payment_provider: provider,

    status: :deferred,
    purchased_at: nil,
    purchased_by: nil,

    deferred_at: (deferred_at.presence || Time.zone.now),
    deferred_by: (deferred_by.presence || current_user)
  )

  # Went from delayed to cheque
  if delayed_payment? && !delayed_payment_provider?
    assign_attributes(delayed_payment_intent: nil, delayed_payment_total: nil)
  end

  if current_user&.email.present?
    assign_attributes(email: current_user.email)
  end

  error = nil

  begin
    Effective::Order.transaction do
      run_purchasable_callbacks(:before_defer)
      save!(validate: validate)
      run_purchasable_callbacks(:after_defer)
    end
  rescue => e
    self.status = status_was
    error = e.message
  end

  raise "Failed to defer order: #{error || errors.full_messages.to_sentence}" unless error.nil?

  send_order_emails! if email

  true
end

#deferred_payment_provider?Boolean

Returns:

  • (Boolean)


590
591
592
# File 'app/models/effective/order.rb', line 590

def deferred_payment_provider?
  payment_provider.present? && EffectiveOrders.deferred_providers.include?(payment_provider)
end

#delay!(payment:, payment_intent:, provider:, card:, email: true, validate: true) ⇒ Object

This was submitted via the deluxe_delayed provider checkout This is a special case of a deferred provider. We require the payment_intent and payment info



779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
# File 'app/models/effective/order.rb', line 779

def delay!(payment:, payment_intent:, provider:, card:, email: true, validate: true)
  raise('expected payment intent to be a String') unless payment_intent.kind_of?(String)
  raise('expected a delayed payment provider') unless EffectiveOrders.delayed_providers.include?(provider) || mailer_preview
  raise('expected a delayed payment order with a delayed_payment_date') unless delayed_payment? && delayed_payment_date.present?

  assign_attributes(
    delayed_payment_intent: payment_intent, 
    delayed_payment_total: total(),

    payment: payment_to_h(payment),
    payment_card: (card.presence || 'none')
  )

  defer!(provider: provider, email: email, validate: validate)
end

#delayed?Boolean

A new order is created. If the delayed_payment and delayed_payment date are set, it’s a delayed order A delayed order is one in which we have to capture a payment intent for the amount of the order. Once it’s delayed and deferred we can purchase it at anytime.

Returns:

  • (Boolean)


598
599
600
# File 'app/models/effective/order.rb', line 598

def delayed?
  delayed_payment? && delayed_payment_date.present?
end

#delayed_payment_date_past?Boolean

Returns:

  • (Boolean)


620
621
622
623
# File 'app/models/effective/order.rb', line 620

def delayed_payment_date_past?
  return false unless delayed?
  delayed_payment_date <= Time.zone.now.to_date
end

#delayed_payment_date_today?Boolean

Returns:

  • (Boolean)


631
632
633
634
# File 'app/models/effective/order.rb', line 631

def delayed_payment_date_today?
  return false unless delayed?
  delayed_payment_date == Time.zone.now.to_date
end

#delayed_payment_date_upcoming?Boolean

This is checked by an effective_orders view helper. When upcoming we only collect card info.

Returns:

  • (Boolean)


626
627
628
629
# File 'app/models/effective/order.rb', line 626

def delayed_payment_date_upcoming?
  return false unless delayed?
  delayed_payment_date > Time.zone.now.to_date
end

#delayed_payment_infoObject



613
614
615
616
617
618
# File 'app/models/effective/order.rb', line 613

def delayed_payment_info
  return unless delayed? && deferred? && delayed_payment_provider?
  return unless delayed_payment_date_upcoming?

  "Your #{delayed_payment_method} will be charged #{total_to_s} on #{delayed_payment_date.strftime('%A, %B %e, %Y')}."
end

#delayed_payment_methodObject



473
474
475
# File 'app/models/effective/order.rb', line 473

def delayed_payment_method
  payment_method_value if delayed?
end

#delayed_payment_provider?Boolean

Returns:

  • (Boolean)


586
587
588
# File 'app/models/effective/order.rb', line 586

def delayed_payment_provider?
  payment_provider.present? && EffectiveOrders.delayed_providers.include?(payment_provider)
end

#delayed_ready_to_purchase?Boolean

Returns:

  • (Boolean)


602
603
604
605
606
607
608
609
610
611
# File 'app/models/effective/order.rb', line 602

def delayed_ready_to_purchase?
  return false unless delayed? 
  return false unless deferred?
  return false unless delayed_payment_provider?
  return false unless delayed_payment_intent.present?
  return false if delayed_payment_date_upcoming?
  return false if delayed_payment_purchase_ran_at.present? # We ran before and probably failed

  true
end

#deluxe_delayed_purchase!Object



896
897
898
899
900
901
902
903
# File 'app/models/effective/order.rb', line 896

def deluxe_delayed_purchase!
  raise('expected a delayed order') unless delayed?
  raise('expected a deferred order') unless deferred?
  raise('expected delayed payment intent') unless delayed_payment_intent.present?
  raise('expected a deluxe_delayed payment provider') unless payment_provider == 'deluxe_delayed'

  Effective::DeluxeApi.new().purchase_delayed_orders!(self)
end

#done?Boolean

Returns:

  • (Boolean)


494
495
496
# File 'app/models/effective/order.rb', line 494

def done?
  persisted? && (purchased? || declined? || voided? || abandoned?)
end

#duplicateObject



477
478
479
# File 'app/models/effective/order.rb', line 477

def duplicate
  Effective::Order.new(self)
end

#emailsObject

These are all the emails we send all notifications to



906
907
908
# File 'app/models/effective/order.rb', line 906

def emails
  ([purchased_by.try(:email)] + [email] + [user.try(:email)] + Array(organization.try(:billing_emails))).map(&:presence).compact.uniq
end

#emails_send_toObject

Doesn’t control anything. Purely for the flash messaging



911
912
913
# File 'app/models/effective/order.rb', line 911

def emails_send_to
  (emails + [cc.presence]).compact.uniq.to_sentence
end

#free?Boolean

Returns:

  • (Boolean)


578
579
580
# File 'app/models/effective/order.rb', line 578

def free?
  total == 0
end

#full_to_sObject



430
431
432
# File 'app/models/effective/order.rb', line 430

def full_to_s
  [to_s, billing_name.presence, email.presence, total_to_s].compact.join(' - ')
end

#in_progress?Boolean

Returns:

  • (Boolean)


490
491
492
# File 'app/models/effective/order.rb', line 490

def in_progress?
  pending? || confirmed? || deferred?
end

#labelObject



447
448
449
450
451
452
453
454
455
456
457
458
459
# File 'app/models/effective/order.rb', line 447

def label
  if refund? && purchased?
    'Refund'
  elsif purchased?
    'Receipt'
  elsif refund? && (pending? || confirmed?)
    'Pending refund'
  elsif (pending? || confirmed?)
    'Pending order'
  else
    'Order'
  end
end

#log_changes_formatted_value(attribute, value) ⇒ Object



964
965
966
# File 'app/models/effective/order.rb', line 964

def log_changes_formatted_value(attribute, value)
  "#{value.to_s.first(8)}...#{value.to_s.last(4)}" if attribute == :delayed_payment_intent && value.present?
end

#mark_as_purchased!Object

Call this as a way to skip over non consequential orders And mark some purchasables purchased This is different than the Mark as Paid payment processor



703
704
705
# File 'app/models/effective/order.rb', line 703

def mark_as_purchased!
  purchase!(skip_buyer_validations: true, email: false, skip_quickbooks: true)
end

#num_itemsObject



643
644
645
# File 'app/models/effective/order.rb', line 643

def num_items
  present_order_items.map { |oi| oi.quantity }.sum
end

#paymentObject



574
575
576
# File 'app/models/effective/order.rb', line 574

def payment
  Hash(self[:payment])
end

#payment_methodObject



469
470
471
# File 'app/models/effective/order.rb', line 469

def payment_method
  payment_method_value if purchased?
end

#pending!Object

This is called from admin/orders#create This is intended for use as an admin action only It skips any address or bad user validations It’s basically the same as save! on a new order, except it might send the payment request to buyer



655
656
657
658
659
660
661
662
663
664
665
666
667
# File 'app/models/effective/order.rb', line 655

def pending!
  return false if purchased?

  assign_attributes(status: :pending)
  self.addresses.clear if addresses.any? { |address| address.valid? == false }
  save!

  if send_payment_request?
    after_commit { send_payment_request! }
  end

  true
end

#pending_refund?Boolean

Returns:

  • (Boolean)


636
637
638
639
640
641
# File 'app/models/effective/order.rb', line 636

def pending_refund?
  return false if EffectiveOrders.buyer_purchases_refund?
  return false if purchased?

  refund?
end

#purchasablesObject



522
523
524
# File 'app/models/effective/order.rb', line 522

def purchasables
  present_order_items.map { |order_item| order_item.purchasable }.compact
end

#purchase!(payment: nil, provider: nil, card: nil, email: true, skip_buyer_validations: false, skip_quickbooks: false) ⇒ Object

Effective::Order.new(items: Product.first, user: User.first).purchase!(email: false)



708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
# File 'app/models/effective/order.rb', line 708

def purchase!(payment: nil, provider: nil, card: nil, email: true, skip_buyer_validations: false, skip_quickbooks: false)
  return true if purchased?

  raise('unable to purchase voided order') if voided?

  # Assign attributes
  assign_attributes(
    skip_buyer_validations: skip_buyer_validations,

    status: :purchased,
    purchased_at: (purchased_at.presence || Time.zone.now),
    purchased_by: (purchased_by.presence || current_user),

    payment: payment_to_h(payment.presence || 'none'),
    payment_provider: (provider.presence || 'none'),
    payment_card: (card.presence || 'none'),

    delayed_payment_intent: nil # Do not store the delayed payment intent any longer
  )

  if current_user&.email.present?
    assign_attributes(email: current_user.email)
  end

  # Updates surcharge and total based on payment_provider
  assign_order_charges()

  begin
    Effective::Order.transaction do
      run_purchasable_callbacks(:before_purchase)

      save!
      update_purchasables_purchased_order!

      run_purchasable_callbacks(:after_purchase)
    end
  rescue => e
    Effective::Order.transaction do
      save!(validate: false)
      update_purchasables_purchased_order!
    end

    raise(e)
  end

  send_order_emails! if email
  after_commit { sync_quickbooks!(skip: skip_quickbooks) }

  true
end

#purchased?(provider = nil) ⇒ Boolean

Returns:

  • (Boolean)


504
505
506
507
508
# File 'app/models/effective/order.rb', line 504

def purchased?(provider = nil)
  return false if (status.to_sym != :purchased)
  return true if provider.nil? || payment_provider == provider.to_s
  false
end

#purchased_or_deferred?Boolean

Returns:

  • (Boolean)


510
511
512
# File 'app/models/effective/order.rb', line 510

def purchased_or_deferred?
  purchased? || deferred?
end

#purchased_with_credit_card?Boolean

Returns:

  • (Boolean)


514
515
516
# File 'app/models/effective/order.rb', line 514

def purchased_with_credit_card?
  purchased? && EffectiveOrders.credit_card_payment_providers.include?(payment_provider)
end

#purchased_without_credit_card?Boolean

Returns:

  • (Boolean)


518
519
520
# File 'app/models/effective/order.rb', line 518

def purchased_without_credit_card?
  purchased? && EffectiveOrders.credit_card_payment_providers.exclude?(payment_provider)
end

#qb_online_customer_display_nameObject



434
435
436
437
438
439
440
441
442
443
444
445
# File 'app/models/effective/order.rb', line 434

def qb_online_customer_display_name
  return billing_name if billing_first_name.blank? || billing_last_name.blank?

  case EffectiveOrders.qb_online_customer_display_name_format
  when :first_last
    "#{billing_first_name} #{billing_last_name}"
  when :last_first
    "#{billing_last_name}, #{billing_first_name}"
  else
    raise("invalid qb_online_customer_display_name_format: #{EffectiveOrders.qb_online_customer_display_name_format}")
  end
end

#refund?Boolean

Returns:

  • (Boolean)


582
583
584
# File 'app/models/effective/order.rb', line 582

def refund?
  total.to_i < 0
end

#remove(*items) ⇒ Object



333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
# File 'app/models/effective/order.rb', line 333

def remove(*items)
  raise 'unable to alter a purchased order' if purchased?
  raise 'unable to alter a declined order' if declined?

  removed = items.map do |item|
    order_item = if item.kind_of?(Effective::OrderItem)
      order_items.find { |oi| oi == item }
    else
      order_items.find { |oi| oi.purchasable == item }
    end

    raise("Unable to find order item for #{item}") if order_item.blank?
    order_item
  end

  removed.each { |order_item| order_item.mark_for_destruction }

  # Make sure to reset stored aggregates
  assign_attributes(subtotal: nil, tax_rate: nil, tax: nil, amount_owing: nil, surcharge_percent: nil, surcharge: nil, surcharge_tax: nil, total: nil)

  removed.length == 1 ? removed.first : removed
end

#reportable_scopesObject

effective_reports



171
172
173
# File 'app/models/effective/order.rb', line 171

def reportable_scopes
  { purchased: nil, not_purchased: nil, deferred: nil, refunds: nil, pending_refunds: nil }
end

#send_event_registrants_cancelled_email!Object



960
961
962
# File 'app/models/effective/order.rb', line 960

def send_event_registrants_cancelled_email!
  EffectiveOrders.send_email(:order_email, self, event_registrants_cancelled: true)
end

#send_order_email!Object

Admin datatable action



953
954
955
956
957
958
# File 'app/models/effective/order.rb', line 953

def send_order_email!
  return unless purchased_or_deferred?

  EffectiveOrders.send_email(:order_email, self)
  EffectiveOrders.send_email(:order_email_to_admin, self) if EffectiveOrders.send_order_receipt_to_admin
end

#send_order_emails!Object

Used internally to send emails to the buyer or admin depending on order status



922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
# File 'app/models/effective/order.rb', line 922

def send_order_emails!
  return false if skip_order_emails?

  if purchased_or_deferred?
    EffectiveOrders.send_email(:order_email, self) if EffectiveOrders.send_order_receipt_to_buyer
    EffectiveOrders.send_email(:order_email_to_admin, self) if EffectiveOrders.send_order_receipt_to_admin
  end

  if declined?
    EffectiveOrders.send_email(:order_email, self) if EffectiveOrders.send_order_declined_to_buyer
    EffectiveOrders.send_email(:order_email_to_admin, self) if EffectiveOrders.send_order_declined_to_admin
  end

  if refund?
    EffectiveOrders.send_email(:refund_notification_to_admin, self) if EffectiveOrders.send_refund_notification_to_admin
  end
end

#send_payment_request!Object

Admin datatable action



945
946
947
948
949
950
# File 'app/models/effective/order.rb', line 945

def send_payment_request!
  return if (purchased_or_deferred? || refund?)

  EffectiveOrders.send_email(:order_email, self, payment_request: true)
  EffectiveOrders.send_email(:order_email_to_admin, self, payment_request: true) if EffectiveOrders.send_payment_request_to_admin
end

#send_payment_request?Boolean

Returns:

  • (Boolean)


940
941
942
# File 'app/models/effective/order.rb', line 940

def send_payment_request?
  EffectiveResources.truthy?(send_payment_request)
end

#skip_buyer_validations?Boolean

Returns:

  • (Boolean)


647
648
649
# File 'app/models/effective/order.rb', line 647

def skip_buyer_validations?
  EffectiveResources.truthy?(skip_buyer_validations)
end

#skip_order_emails?Boolean

Returns:

  • (Boolean)


915
916
917
918
919
# File 'app/models/effective/order.rb', line 915

def skip_order_emails?
  return true if purchased? && free? && !EffectiveOrders.send_order_receipts_when_free
  return true if purchased? && free? && OrderEmail.new(self).event_all_waitlisted_or_archived?
  false
end

#skip_quickbooks!Object



773
774
775
# File 'app/models/effective/order.rb', line 773

def skip_quickbooks!
  sync_quickbooks!(skip: true)
end

#subtotalObject



526
527
528
# File 'app/models/effective/order.rb', line 526

def subtotal
  self[:subtotal] || get_subtotal()
end

#surchargeObject



546
547
548
# File 'app/models/effective/order.rb', line 546

def surcharge
  self[:surcharge] || get_surcharge()
end

#surcharge_percentObject



542
543
544
# File 'app/models/effective/order.rb', line 542

def surcharge_percent
  self[:surcharge_percent] || get_surcharge_percent()
end

#surcharge_taxObject



550
551
552
# File 'app/models/effective/order.rb', line 550

def surcharge_tax
  self[:surcharge_tax] || get_surcharge_tax()
end

#sync_quickbooks!(skip:) ⇒ Object

We support two different Quickbooks synchronization gems: effective_qb_sync and effective_qb_online



760
761
762
763
764
765
766
767
768
769
770
771
# File 'app/models/effective/order.rb', line 760

def sync_quickbooks!(skip:)
  if EffectiveOrders.qb_online?
    skip ||= (EffectiveOrders.qb_online_sync_free_orders? if free?)
    skip ? EffectiveQbOnline.skip_order!(self) : EffectiveQbOnline.sync_order!(self)
  end

  if EffectiveOrders.qb_sync?
    skip ? EffectiveQbSync.skip_order!(self) : true # Nothing to do
  end

  true
end

#taxObject



534
535
536
# File 'app/models/effective/order.rb', line 534

def tax
  self[:tax] || get_tax()
end

#tax_rateObject



530
531
532
# File 'app/models/effective/order.rb', line 530

def tax_rate
  self[:tax_rate] || get_tax_rate()
end

#tax_to_fObject



562
563
564
# File 'app/models/effective/order.rb', line 562

def tax_to_f
  ((tax || 0) / 100.0).to_f
end

#to_sObject



426
427
428
# File 'app/models/effective/order.rb', line 426

def to_s
  [label, ' #', to_param].join
end

#totalObject



554
555
556
# File 'app/models/effective/order.rb', line 554

def total
  self[:total] || get_total()
end

#total_labelObject



461
462
463
# File 'app/models/effective/order.rb', line 461

def total_label
  purchased? ? 'Total paid' : 'Total due'
end

#total_to_fObject



558
559
560
# File 'app/models/effective/order.rb', line 558

def total_to_f
  ((total || 0) / 100.0).to_f
end

#total_to_sObject



465
466
467
# File 'app/models/effective/order.rb', line 465

def total_to_s
  "$#{'%0.2f' % total_to_f}"
end

#total_with_surchargeObject



566
567
568
# File 'app/models/effective/order.rb', line 566

def total_with_surcharge
  get_total_with_surcharge()
end

#total_without_surchargeObject



570
571
572
# File 'app/models/effective/order.rb', line 570

def total_without_surcharge
  get_total_without_surcharge()
end

#transaction_id(short: false) ⇒ Object

For moneris and moneris_checkout. Just a unique value. Must be 50 characters or fewer or will raise moneris error.



482
483
484
485
486
487
488
# File 'app/models/effective/order.rb', line 482

def transaction_id(short: false)
  if short
    [to_param, Time.zone.now.to_i].compact.join('-')
  else
    [to_param, billing_name.to_s.parameterize.first(20).presence, Time.zone.now.to_i, rand(1000..9999)].compact.join('-')
  end
end

#unvoid!Object



891
892
893
894
# File 'app/models/effective/order.rb', line 891

def unvoid!
  raise('order must be voided to unvoid') unless voided?
  unvoided!(skip_buyer_validations: true)
end

#update_prices!Object



409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# File 'app/models/effective/order.rb', line 409

def update_prices!
  raise('already purchased') if purchased?
  raise('must be pending or confirmed') unless pending? || confirmed?

  present_order_items.each do |item|
    purchasable = item.purchasable

    if purchasable.blank? || purchasable.marked_for_destruction?
      item.mark_for_destruction
    else
      item.assign_purchasable_attributes
    end
  end

  save!
end

#update_purchasable_attributesObject

Called by effective_memberships to update prices from purchasable fees Not called internally



690
691
692
# File 'app/models/effective/order.rb', line 690

def update_purchasable_attributes
  present_order_items.each { |oi| oi.update_purchasable_attributes }
end

#update_purchasable_attributes!Object



694
695
696
697
698
# File 'app/models/effective/order.rb', line 694

def update_purchasable_attributes!
  raise('cannot update purchasable attributes of a purchased order') if purchased?
  update_purchasable_attributes
  save!
end

#void!Object



886
887
888
889
# File 'app/models/effective/order.rb', line 886

def void!
  raise('already voided') if voided?
  voided!(skip_buyer_validations: true)
end