#!/usr/bin/env ruby # frozen_string_literal: true require "optparse" require "date" require_relative "../lib/boot" options = { fix: false, from: nil, to: nil, gc: nil, shine: nil } OptionParser.new do |opts| opts.banner = <<~BANNER Usage: bin/reconcile --from DATE --to DATE --gc PATH [--shine PATH] [--fix] Options: BANNER opts.on("--from DATE", "Start date (YYYY-MM-DD), inclusive") do |v| options[:from] = Date.parse(v) end opts.on("--to DATE", "End date (YYYY-MM-DD), inclusive") do |v| options[:to] = Date.parse(v) end opts.on("--gc PATH", "GoCardless payments CSV file path") do |v| options[:gc] = v end opts.on("--shine PATH", "Shine bank statement CSV file path (optional)") do |v| options[:shine] = v end opts.on("--fix", "Apply fixes: mark matching Dolibarr invoices as paid via API") do options[:fix] = true end opts.on("-h", "--help", "Show this help") do puts opts exit end end.parse! # Validate required options errors = [] errors << "--from is required" unless options[:from] errors << "--to is required" unless options[:to] errors << "--gc is required" unless options[:gc] errors << "--gc file not found: #{options[:gc]}" if options[:gc] && !File.exist?(options[:gc]) errors << "--shine file not found: #{options[:shine]}" if options[:shine] && !File.exist?(options[:shine]) unless errors.empty? errors.each { |e| warn "Error: #{e}" } exit 1 end # Run reconciliation client = Dolibarr::Client.new fetcher = Reconciliation::DolibarrFetcher.new(client, from: options[:from], to: options[:to]) gc_data = Reconciliation::GocardlessParser.parse(options[:gc], from: options[:from], to: options[:to]) shine_data = options[:shine] ? Reconciliation::ShineParser.parse(options[:shine]) : [] dolibarr_invoices = fetcher.fetch_invoices engine = Reconciliation::Engine.new( dolibarr_invoices: dolibarr_invoices, gc_payments: gc_data, shine_transactions: shine_data, from: options[:from], to: options[:to] ) result = engine.run reporter = Reconciliation::Reporter.new(result, from: options[:from], to: options[:to]) reporter.print_summary if options[:fix] fixer = Reconciliation::Fixer.new(client) fixer.apply(result[:gc_paid_dolibarr_open]) end reporter.write_csv