@@ -132,9 +132,69 @@ module Freeagent
132132 end
133133 end
134134
135+ class Invoices < Thor
136+ no_commands do
137+ def api
138+ @api ||= API . new
139+ end
140+
141+ def contacts
142+ @contacts ||= Hash . new { |cache , url | cache [ url ] = api . contact url . split ( '/' ) . last }
143+ end
144+
145+ def projects
146+ @projects ||= Hash . new { |cache , url | cache [ url ] = api . project url . split ( '/' ) . last }
147+ end
148+
149+ def human invoice
150+ [
151+ Date ::parse ( invoice . dated_on ) . strftime ( '%a %d %b %Y' ) ,
152+ Date ::parse ( invoice . due_on ) . strftime ( '%a %d %b %Y' ) ,
153+ invoice . contact_name ,
154+ projects [ invoice . project ] . name ,
155+ invoice . reference ,
156+ invoice . total_value ,
157+ invoice . net_value ,
158+ ] . join ( "\t " )
159+ end
160+ end
161+
162+ STATUSES = %i[ all recent_open_or_overdue open overdue open_or_overdue draft paid scheduled_to_email thank_you_emails reminder_emails ]
163+
164+ desc 'list [-C CONTACT] [-P PROJECT] [-S STATUS] [-f FROM] [-t TO]' , "List invoices"
165+ method_option :contact , aliases : '-C' , type : :string , default : nil , desc : "Limit to a contact, identified by name or email"
166+ method_option :project , aliases : '-P' , type : :string , default : nil , desc : "Limit to a project, identified by name"
167+ method_option :status , aliases : '-S' , type : :string , default : nil , desc : "Invoices that match a status, one of: #{ STATUSES . join ( ', ' ) } "
168+ method_option :from , aliases : '-f' , type : :string , default : nil , desc : 'Date to list invoices from'
169+ method_option :to , aliases : '-t' , type : :string , default : nil , desc : 'Date to list invoices to'
170+ method_option :format , type : :string , default : 'human' , desc : 'Output format, one of human or json'
171+ def list
172+ from = options [ :from ] . nil? ? nil : Date ::parse ( options [ :from ] )
173+ to = options [ :to ] . nil? ? nil : Date ::parse ( options [ :to ] )
174+ status = options [ :status ] . nil? ? nil : match ( :status , STATUSES , options [ :status ] , :to_s )
175+ contact = options [ :contact ] . nil? ? nil : match ( :contact , api . contacts , options [ :contact ] , :first_name , :last_name , :organisation_name , :email , :billing_email )
176+ project = options [ :project ] . nil? ? nil : match ( :project , api . projects , options [ :project ] , :name )
177+
178+ contacts [ contact . url ] = contact unless contact . nil?
179+ projects [ project . url ] = project unless project . nil?
180+ api . invoices ( contact : contact , project : project , view : status ) . select do |invoice |
181+ from . nil? || Date ::parse ( invoice . dated_on ) >= from
182+ end . each do |invoice |
183+ puts case options [ :format ] . downcase
184+ when 'human' ; human ( invoice )
185+ when 'json' ; invoice . to_json
186+ else raise ArgumentError , "unknown output format #{ options [ :format ] } "
187+ end
188+ end
189+ end
190+ end
191+
135192 class Command < Thor
136193 desc "timeslips" , "Create, read, update and delete timeslips"
137194 subcommand "timeslips" , Timeslips
195+
196+ desc "invoices" , "Create, read, update and delete invoices"
197+ subcommand "invoices" , Invoices
138198 end
139199end
140200
0 commit comments