Class: CloverSandboxSimulator::Services::Clover::PaymentService

Inherits:
BaseService
  • Object
show all
Defined in:
lib/clover_sandbox_simulator/services/clover/payment_service.rb

Overview

Manages Clover payments Supports both Platform API payments (non-card) and Ecommerce API (card payments)

For card payments, use the Ecommerce API methods which create real charges that can be properly refunded.

Instance Attribute Summary

Attributes inherited from BaseService

#config, #logger

Instance Method Summary collapse

Constructor Details

#initialize(config: nil) ⇒ PaymentService

Returns a new instance of PaymentService.



12
13
14
15
# File 'lib/clover_sandbox_simulator/services/clover/payment_service.rb', line 12

def initialize(config: nil)
  super
  @ecommerce_service = nil
end

Instance Method Details

#ecommerce_available?Boolean

Check if Ecommerce API is available for card payments

Returns:

  • (Boolean)


131
132
133
# File 'lib/clover_sandbox_simulator/services/clover/payment_service.rb', line 131

def ecommerce_available?
  config.ecommerce_enabled?
end

#ecommerce_serviceObject

Get the Ecommerce service



190
191
192
# File 'lib/clover_sandbox_simulator/services/clover/payment_service.rb', line 190

def ecommerce_service
  @ecommerce_service ||= EcommerceService.new(config: config)
end

#generate_tip(subtotal) ⇒ Object

Generate a random tip amount (15-25% of subtotal)



123
124
125
126
# File 'lib/clover_sandbox_simulator/services/clover/payment_service.rb', line 123

def generate_tip(subtotal)
  tip_percentage = rand(15..25)
  (subtotal * tip_percentage / 100.0).round
end

#get_paymentsObject

Fetch all payments



18
19
20
21
22
# File 'lib/clover_sandbox_simulator/services/clover/payment_service.rb', line 18

def get_payments
  logger.info "Fetching payments..."
  response = request(:get, endpoint("payments"))
  response&.dig("elements") || []
end

#process_card_payment(amount:, card_type: :visa, order_id: nil) ⇒ Hash?

Process a card payment using Ecommerce API Creates a real charge that can be refunded

Parameters:

  • amount (Integer)

    Amount in cents

  • card_type (Symbol) (defaults to: :visa)

    Type of test card (:visa, :mastercard, :amex, :discover)

  • order_id (String, nil) (defaults to: nil)

    Optional order ID to link

Returns:

  • (Hash, nil)

    Charge response with id



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/clover_sandbox_simulator/services/clover/payment_service.rb', line 142

def process_card_payment(amount:, card_type: :visa, order_id: nil)
  unless ecommerce_available?
    logger.warn "Ecommerce API not configured, cannot process card payment"
    return nil
  end

  logger.info "Processing card payment: $#{amount / 100.0} (#{card_type})"

  # Create card token
  token = ecommerce_service.create_test_card_token(card_type: card_type)
  return nil unless token && token["id"]

  # Create charge
  charge = ecommerce_service.create_charge(
    amount: amount,
    source: token["id"],
    order_id: order_id
  )

  if charge && charge["id"]
    logger.info "Card payment successful: #{charge['id']} - $#{charge['amount'] / 100.0}"
  end

  charge
end

#process_card_payment_with_tip(subtotal:, tip_amount:, card_type: :visa) ⇒ Hash?

Process a card payment with tip

Parameters:

  • subtotal (Integer)

    Subtotal amount in cents

  • tip_amount (Integer)

    Tip amount in cents

  • card_type (Symbol) (defaults to: :visa)

    Type of test card

Returns:

  • (Hash, nil)

    Charge response



174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/clover_sandbox_simulator/services/clover/payment_service.rb', line 174

def process_card_payment_with_tip(subtotal:, tip_amount:, card_type: :visa)
  total = subtotal + tip_amount
  logger.info "Processing card payment with tip: $#{subtotal / 100.0} + $#{tip_amount / 100.0} tip"

  charge = process_card_payment(amount: total, card_type: card_type)

  if charge
    # Add tip info to response for tracking
    charge["tip_amount"] = tip_amount
    charge["subtotal"] = subtotal
  end

  charge
end

#process_payment(order_id:, amount:, tender_id:, employee_id:, tip_amount: 0, tax_amount: 0) ⇒ Hash?

Process a payment for an order

Parameters:

  • order_id (String)

    The order ID

  • amount (Integer)

    Subtotal amount in cents (before tip/tax)

  • tender_id (String)

    The tender ID to use

  • employee_id (String)

    The employee processing payment

  • tip_amount (Integer) (defaults to: 0)

    Tip amount in cents

  • tax_amount (Integer) (defaults to: 0)

    Tax amount in cents

Returns:

  • (Hash, nil)

    Payment response or nil on failure



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
# File 'lib/clover_sandbox_simulator/services/clover/payment_service.rb', line 33

def process_payment(order_id:, amount:, tender_id:, employee_id:, tip_amount: 0, tax_amount: 0)
  logger.info "Processing payment for order #{order_id}: $#{amount / 100.0} + tip $#{tip_amount / 100.0} + tax $#{tax_amount / 100.0}"

  payload = {
    "order" => { "id" => order_id },
    "tender" => { "id" => tender_id },
    "employee" => { "id" => employee_id },
    "offline" => false,
    "amount" => amount,
    "tipAmount" => tip_amount,
    "taxAmount" => tax_amount,
    "transactionSettings" => {
      "disableCashBack" => false,
      "cloverShouldHandleReceipts" => true,
      "forcePinEntryOnSwipe" => false,
      "disableRestartTransactionOnFailure" => false,
      "allowOfflinePayment" => false,
      "approveOfflinePaymentWithoutPrompt" => false,
      "forceOfflinePayment" => false,
      "disableReceiptSelection" => false,
      "disableDuplicateCheck" => false,
      "autoAcceptPaymentConfirmations" => false,
      "autoAcceptSignature" => false,
      "returnResultOnTransactionComplete" => false,
      "disableCreditSurcharge" => false
    }
  }

  response = request(:post, endpoint("orders/#{order_id}/payments"), payload: payload)

  if response && response["id"]
    logger.info "Payment successful: #{response["id"]}"
  else
    logger.error "Payment failed: #{response.inspect}"
  end

  response
end

#process_split_payment(order_id:, total_amount:, tip_amount:, tax_amount:, employee_id:, splits:) ⇒ Array<Hash>

Process split payment across multiple tenders

Parameters:

  • order_id (String)

    The order ID

  • total_amount (Integer)

    Total amount including tax (before tip)

  • tip_amount (Integer)

    Total tip amount

  • tax_amount (Integer)

    Tax amount

  • employee_id (String)

    Employee ID

  • splits (Array<Hash>)

    Array of { tender:, percentage: } hashes

Returns:

  • (Array<Hash>)

    Array of payment responses



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
# File 'lib/clover_sandbox_simulator/services/clover/payment_service.rb', line 81

def process_split_payment(order_id:, total_amount:, tip_amount:, tax_amount:, employee_id:, splits:)
  logger.info "Processing split payment for order #{order_id} across #{splits.size} tenders"

  payments = []
  remaining_amount = total_amount
  remaining_tip = tip_amount

  splits.each_with_index do |split, index|
    tender = split[:tender]
    percentage = split[:percentage]
    is_last = (index == splits.size - 1)

    # Calculate this payment's portion
    if is_last
      payment_amount = remaining_amount
      payment_tip = remaining_tip
    else
      payment_amount = (total_amount * percentage / 100.0).round
      payment_tip = (tip_amount * percentage / 100.0).round
      remaining_amount -= payment_amount
      remaining_tip -= payment_tip
    end

    # Tax only on first payment
    payment_tax = index.zero? ? tax_amount : 0

    payment = process_payment(
      order_id: order_id,
      amount: payment_amount,
      tender_id: tender["id"],
      employee_id: employee_id,
      tip_amount: payment_tip,
      tax_amount: payment_tax
    )

    payments << payment if payment
  end

  payments
end

#refund_card_payment(charge_id:, amount: nil) ⇒ Hash?

Create a refund for a card payment

Parameters:

  • charge_id (String)

    The charge ID to refund

  • amount (Integer, nil) (defaults to: nil)

    Amount to refund (nil for full)

Returns:

  • (Hash, nil)

    Refund response



199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/clover_sandbox_simulator/services/clover/payment_service.rb', line 199

def refund_card_payment(charge_id:, amount: nil)
  unless ecommerce_available?
    logger.warn "Ecommerce API not configured, cannot refund card payment"
    return nil
  end

  if amount
    logger.info "Refunding card payment #{charge_id}: $#{amount / 100.0}"
  else
    logger.info "Fully refunding card payment #{charge_id}"
  end

  ecommerce_service.create_refund(charge_id: charge_id, amount: amount)
end