hcp 2.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 49b3c65ad4efe2c4a1d58b08001acdeaad85d0a67d3d7c22e53596f1e6e47378
4
- data.tar.gz: 9e7aaf1f8095223ddcf3d8d3bffe8f04e0478573c4adaf3f6c7bfb843d782359
3
+ metadata.gz: 4d401d8b087f9b1c05637aaad2f69c6f343ff3d8d50809c02d1b12f6d3fa2889
4
+ data.tar.gz: e58432a01d9530029c912b92451c9e94101dd8de0982ca072fb540572d14cbfb
5
5
  SHA512:
6
- metadata.gz: be5b0a3350884a96232554a0b3f44539a5aca0bec65ee4d42fdc6ca332a75d69159ca03ada11a422eacd8711d352b0e6f4119ec48b16a7388f7d1fc9a9e6913d
7
- data.tar.gz: b0f80e696be5103618a7a63e056b2fc14747374f925da2003799be4bac9d4a84c274f21ef41457c0e6865ee968d955bee9043d5d5a13dd3cffe5bd1d11be2dd9
6
+ metadata.gz: 9254b6d9c951494705a671b09484a8bef8586ca085e5a75b3101e66811179cdadd1239e6dd3598d80b9aa097bc0b6a9e7deb982351abc74c48de6f224a7320d8
7
+ data.tar.gz: 0afdf26a35fa1a7c36e8862d272e39590b02f1d7462393bc972379c6a51a32d7f210c02ff9a0788ef0b973bb02259063d489503abc2bbab43ddfe487b1fe5fc1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [3.0.1] - 2026-09-15
4
+
5
+ - [Fix] `visit.anytime?` answers false on an estimate's slot rather than nil. Housecall Pro
6
+ books an estimate for an hour and has no anytime to answer with, so the slot named none --
7
+ and a caller storing what a visit reads had a nil where it expected a yes or a no.
8
+
9
+ ## [3.0.0] - 2026-09-15
10
+
11
+ - [Breaking change] The vocabulary is `company` 2.1: a `Company::Selection` takes its rule as a
12
+ block, a visit answers a lead as well as a job, and it says where it is. The pin is `~> 2.1`.
13
+
14
+ - [Breaking change] `account.visits` is every stop booked, not only a job's: an estimate is
15
+ work still being looked at, so its slot is a visit too, and the list now reads `/jobs` and
16
+ `/estimates` rather than `/jobs` alone. `visit.job` is nil on an estimate's slot and
17
+ `visit.lead` is the `Hcp::Estimate`; `visit.description` is nil there, Housecall Pro giving
18
+ an estimate no words of its own. A caller that wants what it had before asks
19
+ `account.visits.for_jobs`, which is the one request it always was, and `for_leads` is the
20
+ estimates alone.
21
+
22
+ - [Feature] `Hcp::Estimate`, a `Company::Lead`: `id`, `customer`, `location`, `technicians` and
23
+ the one slot it is booked for. Housecall Pro expands an estimate with `attachments` and not
24
+ with appointments, so the estimate's own `schedule` is the slot and answers to its ID.
25
+
26
+ - [Feature] `Hcp::Visit#location`, where the stop is: an appointment has no address of its own
27
+ and takes the job's, an estimate's slot takes the estimate's. Both nodes are read in full
28
+ already, so it costs nothing and is always there.
29
+
30
+ - [Feature] `Hcp::Visit#lead`, and `technicians` reading an estimate's `assigned_employees`
31
+ where a job's stop reads its dispatch.
32
+
33
+ - [Feature] `account.technicians` walks the location's employees a page at a time, each an
34
+ `Hcp::Technician` reading `id`, `name` off `first_name` and `surname` off `last_name`.
35
+
36
+ - [Feature] `job.technicians` is the crew a job is assigned to, and `visit.technicians` whoever
37
+ an appointment was dispatched to -- or, where it was dispatched to nobody, the job's whole
38
+ crew, which is how Housecall Pro draws it.
39
+
40
+ - [Feature] `account.visits.between(from, to).assigned_to(technician)` is one technician's
41
+ week. The window goes to Housecall Pro as `employee_ids`, so only their jobs come back, and
42
+ the stops of those jobs they are not on are let go as the jobs arrive.
43
+
3
44
  ## [2.0.0] - 2026-09-09
4
45
 
5
46
  - [Breaking change] The key is one account's: `Hcp::Account.new(key:, company_id:)`, a
data/CLAUDE.md CHANGED
@@ -42,6 +42,27 @@ documented shape. What has been found so far:
42
42
  `Estimate not found` for an option's, so an option is found by listing
43
43
  `GET /estimates?customer_id=` and searching the options. Probed live 2026-09-09.
44
44
 
45
+ - `employee_ids` narrows both `/jobs` and `/estimates` by assigned pro, and `/estimates` takes
46
+ the same `scheduled_start_min`/`scheduled_start_max` window as `/jobs`. Over one year on a
47
+ real account: 15 jobs to 5, and 40 estimates to 2. Worth writing down because the spec gives
48
+ the parameter no description at all on `/jobs` -- only the `/estimates` twin documents it.
49
+ `GET /employees` answers `first_name` and `last_name`. Probed live 2026-09-15.
50
+
51
+ Read off the spec but **not probed**, so treat as claims rather than findings:
52
+
53
+ - `GET /estimates`' `expand` enum is `attachments` alone -- there is no `appointments` on an
54
+ estimate, so its `schedule` is the one slot it occupies. Its `work_status` carries `canceled`.
55
+ - `GET /routes` is the only endpoint that groups a day's work, and is unusable as one: it takes
56
+ a single `date` and `per_page` rather than a range, refuses a Company API Key, and answers
57
+ `event_ids` and `estimate_ids` as bare strings, so the times still cost `/events` and
58
+ `/estimates`.
59
+ - `GET /events` -- time blocked out on the calendar -- takes no date and no employee filter at
60
+ all, so a week of it can only be paged in full. Its `recurrence_rule` is not expanded.
61
+ - `POST /estimates` takes `customer_id`, not a customer, so booking one needs `GET /customers`
62
+ (search by `q`) and `POST /customers` first. The arrival window is spelled three ways:
63
+ `arrival_window_in_minutes` on create, `arrival_window_minutes` on an appointment,
64
+ `arrival_window` on a schedule read back.
65
+
45
66
  A company-scoped key refuses `X-Company-Id` with a 401 on every endpoint, so the header can only
46
67
  be exercised with an application key. `GET /company` answers `locations` only to the latter, and
47
68
  nests: a location holds locations of its own, several levels deep.
data/README.md CHANGED
@@ -13,7 +13,7 @@ gem install hcp
13
13
  Or, in a Gemfile, pinned to the current major:
14
14
 
15
15
  ```ruby
16
- gem 'hcp', '~> 2.0'
16
+ gem 'hcp', '~> 3.0'
17
17
  ```
18
18
 
19
19
  `~> major.minor` means `bundle update` never crosses a breaking change.
@@ -84,18 +84,74 @@ A customer's `name` is their first name, or the business's where a person has no
84
84
 
85
85
  ## Visits
86
86
 
87
- Housecall Pro calls a visit an appointment and files it inside a job, so the visits booked to
88
- start within a window are read off the jobs booked across it, a page of jobs at a time, each
89
- saying what its job says and carrying it. A job called off keeps its visits to itself, and a
90
- list nothing narrows walks every job there was.
87
+ A visit is any booked time, and Housecall Pro books it two ways. Work already won is a job,
88
+ and Housecall Pro calls its stops appointments and files them inside it. Work still being
89
+ looked at is an estimate, which it schedules the same way but hangs no appointments under, so
90
+ an estimate holds the one slot. Both are read off the work booked across the window, a page of
91
+ it at a time; work called off keeps its stops to itself, and a list nothing narrows walks
92
+ every job and estimate there was.
91
93
 
92
94
  ```ruby
93
95
  account.visits.upcoming(2.weeks).each do |visit|
94
- visit.id, visit.description, visit.starts_at, visit.ends_at, visit.anytime?
95
- visit.job # => the Hcp::Job the stop belongs to, its location and customer along
96
+ visit.id, visit.starts_at, visit.ends_at, visit.anytime?
97
+ visit.description # => what the job is called, or nil: an estimate has no words of its own
98
+ visit.location # => where the stop is, whatever it was booked for
99
+ visit.job # => the Hcp::Job the stop belongs to, or nil where an estimate does
100
+ visit.lead # => the Hcp::Estimate it belongs to, or nil where a job does
101
+ visit.technicians # => the Hcp::Technicians the stop is booked for
96
102
  end
97
103
  ```
98
104
 
105
+ The two cost a list each, so a caller that wants one kind asks for it and spends one request:
106
+
107
+ ```ruby
108
+ account.visits.upcoming(2.weeks).for_jobs # => only the appointments, one request
109
+ account.visits.upcoming(2.weeks).for_leads # => only the estimates' slots, one request
110
+ ```
111
+
112
+ A stop says where it is without being asked what it was booked for: an appointment has no
113
+ address of its own and takes the job's, and an estimate's slot takes the estimate's. A caller
114
+ reading a schedule never reaches through `visit.job` for an address.
115
+
116
+ An estimate reads as the lead it is -- `id`, `customer`, `location` -- because its other half,
117
+ the price, is already `Hcp::Quote`: Housecall Pro files the visit and the prices as one record
118
+ and the vocabulary reads them as two.
119
+
120
+ `account.visits.create` is named by the vocabulary and not answered here yet; it raises
121
+ `NotImplementedError`. Booking one means `POST /estimates`, which takes a `customer_id` rather
122
+ than a customer, so it needs `GET /customers` and `POST /customers` first, and all three want
123
+ probing before they are written against.
124
+
125
+ ## The schedule
126
+
127
+ The crew are Housecall Pro's employees, and the active ones are walked a page at a time:
128
+
129
+ ```ruby
130
+ account.technicians.each do |technician|
131
+ technician.id, technician.name, technician.surname
132
+ end
133
+ ```
134
+
135
+ One technician's week is the visits in it narrowed to them, which is how a schedule reads:
136
+
137
+ ```ruby
138
+ monday = Date.today.beginning_of_week.in_time_zone
139
+ account.visits.between(monday, monday + 1.week).assigned_to(technician).each do |visit|
140
+ visit.starts_at, visit.ends_at, visit.job.location.street
141
+ end
142
+ ```
143
+
144
+ Housecall Pro narrows both lists by who is assigned to the work, so the window is asked for as
145
+ that technician's and nobody else's comes back -- verified against a real account, where a year
146
+ of work went from 15 jobs to 5 and from 40 estimates to 2. It narrows no further: a job's appointments are
147
+ dispatched to some of its crew or to none of it, so a stop dispatched to nobody is the whole
148
+ crew's, and the stops the technician is not on are let go once the jobs arrive. Asking for the
149
+ week and asking for the technician narrow the same list, in either order.
150
+
151
+ What Housecall Pro schedules elsewhere is still not here: time blocked out on the calendar is
152
+ filed under `/events`, which takes no date and no employee to narrow by, so a week of it cannot
153
+ be asked for -- only paged in full.
154
+
99
155
  ## Errors
100
156
 
101
157
  Everything descends from `Hcp::Error`, which descends from `Company::Error`, so one rescue
data/lib/hcp/account.rb CHANGED
@@ -16,6 +16,9 @@ module Hcp
16
16
  # @return [Visits] visits of the location, read off its jobs.
17
17
  def visits = Visits.new client: @client
18
18
 
19
+ # @return [Technicians] employees of the location, walked a page at a time.
20
+ def technicians = Technicians.new client: @client
21
+
19
22
  # @return [Leads] leads of the location, to open and to move.
20
23
  def leads = Leads.new client: @client
21
24
  end
@@ -0,0 +1,22 @@
1
+ module Hcp
2
+ # The estimates of one location, walked a page at a time. Housecall Pro narrows them by the
3
+ # same words it narrows jobs by, so a window and a crew cost what they cost on a job.
4
+ class Estimates < Company::Collection
5
+ # @param client [Client] how to reach Housecall Pro as the location.
6
+ # @param params [Hash] what the list is narrowed to, as Housecall Pro filters estimates.
7
+ def initialize(client:, params: {})
8
+ @client = client
9
+ @params = params
10
+ end
11
+
12
+ # Nothing is read until the walk starts, and a page only once the one before it runs out.
13
+ # @yield [Estimate] each estimate in the window, in the order Housecall Pro lists them.
14
+ def each
15
+ (1..).each do |page|
16
+ body = @client.get 'estimates', @params.merge(page: page, page_size: Jobs::PAGE)
17
+ body.fetch('estimates').each { |node| yield Estimate.new node: node }
18
+ break if page >= body.fetch('total_pages')
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ module Hcp
2
+ # The employees of one location, walked a page at a time. Housecall Pro lists the active
3
+ # ones and no others, so a crew that has left the business is not among them.
4
+ class Technicians < Company::Collection
5
+ # Employees a page: the most Housecall Pro answers with, and more than it refuses.
6
+ PAGE = 200
7
+
8
+ # @param client [Client] how to reach Housecall Pro as the location.
9
+ def initialize(client:)
10
+ @client = client
11
+ end
12
+
13
+ # Nothing is read until the walk starts, and a page only once the one before it runs out.
14
+ # @yield [Technician] each employee, in the order Housecall Pro lists them.
15
+ def each
16
+ (1..).each do |page|
17
+ body = @client.get 'employees', page: page, page_size: PAGE
18
+ body.fetch('employees').each { |node| yield Technician.new node: node }
19
+ break if page >= body.fetch('total_pages')
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,39 +1,80 @@
1
1
  module Hcp
2
- # The visits of one location, which Housecall Pro calls appointments and files inside jobs:
3
- # they are read off the jobs booked across a window, a page of jobs at a time.
4
- class Visits < Company::Collection
2
+ # The visits of one location: the appointments Housecall Pro files inside jobs, and the slot
3
+ # it files on each estimate. They are read off the work booked across a window, a page of it
4
+ # at a time, and each kind costs a list of its own.
5
+ class Visits < Company::Visits
5
6
  # @param client [Client] how to reach Housecall Pro as the location.
6
7
  # @param from [Time, nil] the moment the window opens, or nothing for every visit there was.
7
8
  # @param to [Time, nil] the moment the window closes, or nothing for every visit to come.
8
- def initialize(client:, from: nil, to: nil)
9
+ # @param technician [Company::Technician, nil] whose work to ask for, or nothing for all.
10
+ # @param jobs [Boolean] whether to read the stops of jobs.
11
+ # @param leads [Boolean] whether to read the stops of estimates.
12
+ def initialize(client:, from: nil, to: nil, technician: nil, jobs: true, leads: true)
9
13
  @client = client
10
14
  @from = from
11
15
  @to = to
16
+ @technician = technician
17
+ @jobs = jobs
18
+ @leads = leads
12
19
  end
13
20
 
14
21
  # @param from [Time, nil] the moment the window opens, or nothing for every visit there was.
15
22
  # @param to [Time, nil] the moment the window closes, or nothing for every visit to come.
16
23
  # @return [Visits] the same list, narrowed to the visits booked to start between the two.
17
- def between(from, to) = self.class.new(client: @client, from: from, to: to)
24
+ def between(from, to) = with from: from, to: to
18
25
 
19
- # A job booked across the window carries every visit in it, so the jobs are read once and
20
- # a canceled job's visits are left where they are.
21
- # @yield [Visit] each visit in the window, in the order Housecall Pro lists them.
22
- def each
23
- jobs.each do |job|
24
- next if job.canceled?
25
-
26
- job.visits.each { |visit| yield visit if window.cover? visit.starts_at }
26
+ # Housecall Pro narrows both lists by who is assigned to the work, so the window is asked
27
+ # for as this technician's; a job's stop is the whole crew's until somebody is dispatched
28
+ # to it, so the stops they are not on are let go once the work comes back.
29
+ # @param technician [Company::Technician] whoever the work is booked for.
30
+ # @return [Company::Selection] the same list, narrowed to the stops they are booked for.
31
+ def assigned_to(technician)
32
+ theirs = with technician: technician
33
+ Company::Selection.new(collection: theirs) do |visit|
34
+ visit.technicians.any? { |each| each.id == technician.id }
27
35
  end
28
36
  end
29
37
 
38
+ # @return [Visits] the same list, read off the jobs alone: one request rather than two.
39
+ def for_jobs = with leads: false
40
+
41
+ # @return [Visits] the same list, read off the estimates alone: one request rather than two.
42
+ def for_leads = with jobs: false
43
+
44
+ # Work booked across the window carries every stop in it, so each list is read once and
45
+ # what was called off keeps its stops to itself.
46
+ # @yield [Visit] each visit in the window, the jobs' stops before the estimates'.
47
+ def each(&)
48
+ jobs.each { |job| stops job, & } if @jobs
49
+ estimates.each { |estimate| stops estimate, & } if @leads
50
+ end
51
+
30
52
  private
31
53
 
54
+ def with(**changed)
55
+ self.class.new(**{ client: @client, from: @from, to: @to, technician: @technician,
56
+ jobs: @jobs, leads: @leads }.merge(changed))
57
+ end
58
+
59
+ def stops(work)
60
+ return if work.canceled?
61
+
62
+ work.visits.each { |visit| yield visit if window.cover? visit.starts_at }
63
+ end
64
+
32
65
  def window = @from..@to
33
66
 
67
+ def crew = { employee_ids: (@technician && [ @technician.id ]) }
68
+
34
69
  def jobs
35
70
  bounds = { scheduled_end_min: @from&.utc&.iso8601, scheduled_start_max: @to&.utc&.iso8601 }
36
- Jobs.new client: @client, params: bounds.compact.merge(expand: [ 'appointments' ])
71
+ params = bounds.merge(crew).compact.merge expand: [ 'appointments' ]
72
+ Jobs.new client: @client, params: params
73
+ end
74
+
75
+ def estimates
76
+ bounds = { scheduled_start_min: @from&.utc&.iso8601, scheduled_start_max: @to&.utc&.iso8601 }
77
+ Estimates.new client: @client, params: bounds.merge(crew).compact
37
78
  end
38
79
  end
39
80
  end
@@ -0,0 +1,43 @@
1
+ module Hcp
2
+ # Work a Housecall Pro user was asked to look at and price, which the vocabulary reads as the
3
+ # lead it is: a stop to go and see it, before there is a job. Housecall Pro schedules it the
4
+ # way it schedules a job but hangs no appointments under it, so it holds the one slot.
5
+ class Estimate < Company::Lead
6
+ # @return [Customer, nil] customer the estimate was opened for.
7
+ def customer = record Customer, :customer
8
+
9
+ # Housecall Pro files the address and the customer side by side, the way it does on a job.
10
+ # @return [Location, nil] where the work would happen, nil where it is booked nowhere.
11
+ def location
12
+ address = @node[:address]
13
+ Location.new node: address.merge(customer: @node[:customer]) if address[:id].present?
14
+ end
15
+
16
+ # @return [Array<Technician>] employees the estimate is assigned to.
17
+ def technicians = records Technician, :assigned_employees
18
+
19
+ # Housecall Pro gives an estimate no words of its own: what it says is said by its options.
20
+ # @return [nil] nothing, so a stop of one goes undescribed.
21
+ def description = nil
22
+
23
+ # Housecall Pro files no ID on the slot, there being only ever the one, so it answers to the
24
+ # estimate's own, and books it for an hour rather than for any time in a day.
25
+ # @return [Array<Visit>] the one slot the estimate is booked for, empty where it has none.
26
+ def visits
27
+ booked = @node.dig :schedule, :scheduled_start
28
+ return [] if booked.blank?
29
+
30
+ [ Visit.new(node: slot, lead: self) ]
31
+ end
32
+
33
+ # @return [Boolean] whether the customer or the pro called the estimate off.
34
+ def canceled? = attribute(:work_status).to_s.end_with? 'canceled'
35
+
36
+ private
37
+
38
+ def slot
39
+ { id: id, anytime: false, start_time: @node.dig(:schedule, :scheduled_start),
40
+ end_time: @node.dig(:schedule, :scheduled_end) }
41
+ end
42
+ end
43
+ end
@@ -38,6 +38,10 @@ module Hcp
38
38
  # @return [Array<Visit>] stops the job is booked as, empty where none came back.
39
39
  def visits = Array(@node.dig :schedule, :appointments).map { Visit.new node: it, job: self }
40
40
 
41
+ # @return [Array<Technician>] employees the job is assigned to, empty where it is assigned
42
+ # to nobody.
43
+ def technicians = records Technician, :assigned_employees
44
+
41
45
  # @return [Boolean] whether the customer or the pro called the job off.
42
46
  def canceled? = attribute(:work_status).to_s.end_with? 'canceled'
43
47
 
@@ -0,0 +1,7 @@
1
+ module Hcp
2
+ # A person the business sends out, whom Housecall Pro calls an employee.
3
+ class Technician < Company::Technician
4
+ # The node keys Housecall Pro spells otherwise than the vocabulary.
5
+ def self.keys = { name: :first_name, surname: :last_name }
6
+ end
7
+ end
@@ -1,21 +1,45 @@
1
1
  module Hcp
2
- # One stop of a job, which Housecall Pro calls an appointment: it happens where the job does
3
- # and says what the job says.
2
+ # One stop, which Housecall Pro hangs under a job as an appointment and under an estimate as
3
+ # the estimate's own slot: it happens where the work does and says what the work says.
4
4
  class Visit < Company::Visit
5
5
  # The node keys Housecall Pro spells otherwise than the vocabulary.
6
6
  def self.keys = { starts_at: :start_time, ends_at: :end_time }
7
7
 
8
- # @param node [Hash] appointment as Housecall Pro answered it under the job's schedule.
9
- # @param job [Job] job the appointment sits under.
10
- def initialize(node: {}, job:)
8
+ # @param node [Hash] slot as Housecall Pro answered it under the work it belongs to.
9
+ # @param job [Job, nil] job the slot sits under, nil where an estimate does.
10
+ # @param lead [Estimate, nil] estimate the slot sits under, nil where a job does.
11
+ def initialize(node: {}, job: nil, lead: nil)
11
12
  super node: node
12
13
  @job = job
14
+ @lead = lead
13
15
  end
14
16
 
15
- # @return [Job] job the stop belongs to, which came with it.
17
+ # @return [Job, nil] job the stop belongs to, nil where the stop is an estimate's.
16
18
  attr_reader :job
17
19
 
18
- # @return [String, nil] what the job is called: an appointment has no words of its own.
19
- def description = @job.description
20
+ # @return [Estimate, nil] estimate the stop belongs to, nil where the stop is a job's.
21
+ attr_reader :lead
22
+
23
+ # @return [String, nil] what the work is called: a stop has no words of its own.
24
+ def description = work.description
25
+
26
+ # An appointment has no address of its own and an estimate's slot is the estimate's, so a
27
+ # stop is where its work is.
28
+ # @return [Location, nil] where the stop happens, nil where the work is booked nowhere.
29
+ def location = work.location
30
+
31
+ # Housecall Pro dispatches a job's stop to some of its crew, or to none of it, and a stop
32
+ # dispatched to nobody is the whole crew's. An estimate dispatches nothing and has one crew.
33
+ # @return [Array<Technician>] whoever the stop is booked for.
34
+ def technicians = dispatched.presence || work.technicians
35
+
36
+ private
37
+
38
+ def work = @job || @lead
39
+
40
+ def dispatched
41
+ ids = Array attribute(:dispatched_employees_ids)
42
+ work.technicians.select { |technician| ids.include? technician.id }
43
+ end
20
44
  end
21
45
  end
data/lib/hcp/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # The Housecall Pro API, answered in the vocabulary of the company gem.
2
2
  module Hcp
3
3
  # The version of this gem, as RubyGems knows it.
4
- VERSION = '2.0.0'
4
+ VERSION = '3.0.1'
5
5
  end
data/lib/hcp.rb CHANGED
@@ -26,12 +26,16 @@ require 'hcp/collections/leads'
26
26
 
27
27
  # Every record before the one that reads it beside itself, and the job before its list.
28
28
  require 'hcp/resources/customer'
29
+ require 'hcp/resources/technician'
29
30
  require 'hcp/resources/location'
30
31
  require 'hcp/resources/line'
31
32
  require 'hcp/resources/quote'
32
33
  require 'hcp/resources/visit'
33
34
  require 'hcp/resources/job'
35
+ require 'hcp/resources/estimate'
34
36
  require 'hcp/collections/jobs'
37
+ require 'hcp/collections/estimates'
35
38
  require 'hcp/collections/visits'
39
+ require 'hcp/collections/technicians'
36
40
  require 'hcp/account'
37
41
  require 'hcp/event'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claudio Baccigalupo
@@ -29,14 +29,14 @@ dependencies:
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '1.0'
32
+ version: '2.1'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '1.0'
39
+ version: '2.1'
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: minitest
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -137,19 +137,23 @@ files:
137
137
  - lib/hcp/account.rb
138
138
  - lib/hcp/answer.rb
139
139
  - lib/hcp/client.rb
140
+ - lib/hcp/collections/estimates.rb
140
141
  - lib/hcp/collections/jobs.rb
141
142
  - lib/hcp/collections/leads.rb
143
+ - lib/hcp/collections/technicians.rb
142
144
  - lib/hcp/collections/visits.rb
143
145
  - lib/hcp/error.rb
144
146
  - lib/hcp/errors/throttled.rb
145
147
  - lib/hcp/event.rb
146
148
  - lib/hcp/resources/business.rb
147
149
  - lib/hcp/resources/customer.rb
150
+ - lib/hcp/resources/estimate.rb
148
151
  - lib/hcp/resources/job.rb
149
152
  - lib/hcp/resources/lead.rb
150
153
  - lib/hcp/resources/line.rb
151
154
  - lib/hcp/resources/location.rb
152
155
  - lib/hcp/resources/quote.rb
156
+ - lib/hcp/resources/technician.rb
153
157
  - lib/hcp/resources/visit.rb
154
158
  - lib/hcp/version.rb
155
159
  homepage: https://github.com/claudiob/hcp