/
sync_service.rb
141 lines (114 loc) · 5.18 KB
/
sync_service.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# frozen_string_literal: true
# Responsible for ensuring that any updates to a Subscription are propagated to any
# orders belonging to that Subscription which have been instantiated
module Orders
class SyncService
attr_reader :order_update_issues
def initialize(subscription)
@subscription = subscription
@order_update_issues = Orders::UpdateIssuesService.new
@line_item_syncer = LineItemSyncer.new(subscription, order_update_issues)
end
def sync!
orders_in_order_cycles_not_closed.all? do |order|
order.assign_attributes(customer_id:, email: customer&.email,
distributor_id: shop_id)
update_associations_for(order)
line_item_syncer.sync!(order)
order.update_order!
order.save
end
end
private
attr_reader :subscription, :line_item_syncer
delegate :orders, :bill_address, :ship_address, :subscription_line_items, to: :subscription
delegate :shop_id, :customer, :customer_id, to: :subscription
delegate :shipping_method, :shipping_method_id,
:payment_method, :payment_method_id, to: :subscription
delegate :shipping_method_id_changed?, :shipping_method_id_was, to: :subscription
delegate :payment_method_id_changed?, :payment_method_id_was, to: :subscription
def update_associations_for(order)
update_bill_address_for(order) if bill_address.changes.keys.intersect?(relevant_address_attrs)
update_shipment_for(order) if shipping_method_id_changed?
update_ship_address_for(order)
update_payment_for(order) if payment_method_id_changed?
end
def orders_in_order_cycles_not_closed
return @orders_in_order_cycles_not_closed unless @orders_in_order_cycles_not_closed.nil?
@orders_in_order_cycles_not_closed = orders.joins(:order_cycle).
merge(OrderCycle.not_closed).readonly(false)
end
def update_bill_address_for(order)
unless addresses_match?(order.bill_address, bill_address)
return order_update_issues.add(order, I18n.t('bill_address'))
end
order.bill_address.update(bill_address.attributes.slice(*relevant_address_attrs))
end
def update_payment_for(order)
payment = order.payments.
with_state('checkout').where(payment_method_id: payment_method_id_was).last
if payment
payment&.void_transaction!
order.payments.create(payment_method_id:, amount: order.reload.total)
else
unless order.payments.with_state('checkout').where(payment_method_id:).any?
order_update_issues.add(order, I18n.t('admin.payment_method'))
end
end
end
def update_shipment_for(order)
return if pending_shipment_with?(order, shipping_method_id) # No need to do anything.
if pending_shipment_with?(order, shipping_method_id_was)
order.select_shipping_method(shipping_method_id)
else
order_update_issues.add(order, I18n.t('admin.shipping_method'))
end
end
def update_ship_address_for(order)
# The conditions here are to achieve the same behaviour in earlier versions of Spree, where
# switching from pick-up to delivery affects whether simultaneous changes to shipping address
# are ignored or not.
pickup_to_delivery = force_ship_address_required?(order)
if (!pickup_to_delivery || order.shipment.present?) &&
ship_address.changes.keys.intersect?(relevant_address_attrs)
save_ship_address_in_order(order)
end
return unless !pickup_to_delivery || order.shipment.blank?
order.updater.shipping_address_from_distributor
end
def relevant_address_attrs
["firstname", "lastname", "address1", "zipcode", "city", "state_id", "country_id", "phone"]
end
def addresses_match?(order_address, subscription_address)
relevant_address_attrs.all? do |attr|
order_address[attr] == subscription_address.public_send("#{attr}_was") ||
order_address[attr] == subscription_address[attr]
end
end
def ship_address_updatable?(order)
return true if force_ship_address_required?(order)
return false unless order.shipping_method.require_ship_address?
return true if addresses_match?(order.ship_address, ship_address)
order_update_issues.add(order, I18n.t('ship_address'))
false
end
# This returns true when the shipping method on the subscription has changed
# to a delivery (ie. a shipping address is required) AND the existing shipping
# address on the order matches the shop's address
def force_ship_address_required?(order)
return false unless shipping_method.require_ship_address?
distributor_address = order.address_from_distributor
relevant_address_attrs.all? do |attr|
order.ship_address[attr] == distributor_address[attr]
end
end
def save_ship_address_in_order(order)
return unless ship_address_updatable?(order)
order.ship_address.update(ship_address.attributes.slice(*relevant_address_attrs))
end
def pending_shipment_with?(order, shipping_method_id)
return false unless order.shipment.present? && order.shipment.state == "pending"
order.shipping_method.id == shipping_method_id
end
end
end