Standalone Ruby script reconciling GoCardless payments, Dolibarr invoices (via API), and Shine bank statements. Three-pass engine: GC↔Dolibarr matching, open invoice audit, payout↔bank verification. Includes dry-run and --fix mode to auto-mark Dolibarr invoices as paid. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
57 lines
1.8 KiB
Ruby
57 lines
1.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Reconciliation
|
|
# Applies fixes to Dolibarr: marks invoices as paid using GoCardless payment data.
|
|
class Fixer
|
|
def initialize(client)
|
|
@client = client
|
|
end
|
|
|
|
# Accepts an array of Engine::Match objects with flag GC_PAID_DOLIBARR_OPEN
|
|
def apply(matches)
|
|
return if matches.empty?
|
|
|
|
gc_payment_id = ENV.fetch("DOLIBARR_GC_PAYMENT_ID", nil)&.to_i
|
|
bank_id = ENV.fetch("DOLIBARR_BANK_ACCOUNT_ID", "1").to_i
|
|
|
|
if gc_payment_id.nil?
|
|
warn "[Fixer] DOLIBARR_GC_PAYMENT_ID not set in .env — cannot fix. " \
|
|
"Run: GET /setup/dictionary/payment_types to find the GoCardless payment type ID."
|
|
return
|
|
end
|
|
|
|
puts ""
|
|
puts "APPLYING FIXES (#{matches.size} invoices)..."
|
|
|
|
matches.each do |m|
|
|
inv = m.invoice
|
|
pay = m.payment
|
|
|
|
payload = {
|
|
arrayofamounts: {
|
|
inv.id.to_s => {
|
|
amount: "%.2f" % (inv.amount_cents / 100.0),
|
|
multicurrency_amount: nil
|
|
}
|
|
},
|
|
datepaye: pay.charge_date.to_time.to_i,
|
|
paymentid: gc_payment_id,
|
|
closepaidinvoices: "yes",
|
|
accountid: bank_id,
|
|
num_payment: pay.id,
|
|
comment: "GoCardless payment — auto-reconciled (#{pay.charge_date})"
|
|
}
|
|
|
|
begin
|
|
@client.post("/invoices/paymentsdistributed", payload)
|
|
puts " ✓ Marked #{inv.ref} as paid (GC: #{pay.id})"
|
|
rescue Dolibarr::Client::ValidationError => e
|
|
puts " ✗ #{inv.ref} — validation error: #{e.message}"
|
|
rescue Dolibarr::Client::Error => e
|
|
puts " ✗ #{inv.ref} — API error: #{e.message}"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|