Files
dolibarr_shine_reconciliation/lib/reconciliation/fixer.rb
Kevin Bataille 4decb3cb3c Initial implementation of the reconciliation script
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>
2026-02-26 00:23:07 +01:00

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