jbr 3.13.0 → 5.0.0
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 +4 -4
- data/.rubocop.yml +5 -0
- data/CHANGELOG.md +139 -0
- data/README.md +302 -167
- data/lib/graphql/client.rb +2 -6
- data/lib/graphql/error.rb +10 -0
- data/lib/graphql/throttled.rb +0 -9
- data/lib/jbr/account.rb +48 -15
- data/lib/jbr/authorizing.rb +43 -0
- data/lib/jbr/booking.rb +56 -0
- data/lib/jbr/collection.rb +7 -0
- data/lib/jbr/collections/customers.rb +54 -0
- data/lib/jbr/collections/invoices.rb +18 -0
- data/lib/jbr/{jobs.rb → collections/jobs.rb} +8 -8
- data/lib/jbr/collections/leads.rb +30 -0
- data/lib/jbr/collections/locations.rb +47 -0
- data/lib/jbr/collections/quotes.rb +18 -0
- data/lib/jbr/collections/technicians.rb +17 -0
- data/lib/jbr/collections/visits.rb +61 -0
- data/lib/jbr/error.rb +1 -1
- data/lib/jbr/errors/throttled.rb +6 -0
- data/lib/jbr/includable.rb +10 -8
- data/lib/jbr/listable.rb +17 -35
- data/lib/jbr/logger.rb +13 -0
- data/lib/jbr/mock/account.rb +28 -7
- data/lib/jbr/mock/invoice.rb +7 -11
- data/lib/jbr/mock/invoices.rb +7 -0
- data/lib/jbr/mock/jobs.rb +10 -6
- data/lib/jbr/mock/leads.rb +7 -0
- data/lib/jbr/mock/quote.rb +3 -8
- data/lib/jbr/mock/quotes.rb +7 -0
- data/lib/jbr/mock/technicians.rb +12 -0
- data/lib/jbr/mock/visit.rb +9 -16
- data/lib/jbr/mock/visits.rb +39 -6
- data/lib/jbr/mock.rb +17 -4
- data/lib/jbr/phone.rb +5 -8
- data/lib/jbr/querying.rb +68 -0
- data/lib/jbr/reader.rb +9 -0
- data/lib/jbr/reading.rb +15 -0
- data/lib/jbr/refreshing.rb +0 -8
- data/lib/jbr/resources/customer.rb +23 -0
- data/lib/jbr/resources/invoice.rb +29 -0
- data/lib/jbr/resources/job.rb +20 -0
- data/lib/jbr/resources/lead.rb +7 -0
- data/lib/jbr/resources/line.rb +15 -0
- data/lib/jbr/resources/location.rb +31 -0
- data/lib/jbr/resources/quote.rb +15 -0
- data/lib/jbr/resources/technician.rb +19 -0
- data/lib/jbr/resources/visit.rb +30 -0
- data/lib/jbr/scheduled.rb +36 -0
- data/lib/jbr/version.rb +1 -1
- data/lib/jbr.rb +45 -45
- metadata +46 -28
- data/lib/jbr/client.rb +0 -98
- data/lib/jbr/cliental.rb +0 -14
- data/lib/jbr/invoice.rb +0 -43
- data/lib/jbr/itemized.rb +0 -9
- data/lib/jbr/job.rb +0 -40
- data/lib/jbr/line_item.rb +0 -44
- data/lib/jbr/mock/client.rb +0 -17
- data/lib/jbr/mock/job.rb +0 -31
- data/lib/jbr/mock/line_item.rb +0 -16
- data/lib/jbr/mock/oauth.rb +0 -22
- data/lib/jbr/mock/property.rb +0 -19
- data/lib/jbr/mock/request.rb +0 -12
- data/lib/jbr/mock/url.rb +0 -9
- data/lib/jbr/mocking.rb +0 -30
- data/lib/jbr/named.rb +0 -9
- data/lib/jbr/oauth.rb +0 -94
- data/lib/jbr/properted.rb +0 -17
- data/lib/jbr/property.rb +0 -93
- data/lib/jbr/quote.rb +0 -25
- data/lib/jbr/request.rb +0 -37
- data/lib/jbr/resource.rb +0 -26
- data/lib/jbr/retriable.rb +0 -20
- data/lib/jbr/url.rb +0 -16
- data/lib/jbr/visit.rb +0 -24
- data/lib/jbr/visits.rb +0 -36
- /data/lib/jbr/{refused.rb → errors/refused.rb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a01ddd16fc41518ff9cc7d18b61bdc2c0d9e419959c01fc7dd822473de08bade
|
|
4
|
+
data.tar.gz: 3d60fe2c06fd056d0e61d83bca1e40ff6f61954994a061e858a60422b6546e12
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 71b4e3faacce7acb0ea6d5a3eab5f1beea5f4534a416a16ed663d434299551b94375e3522f0152e6627a22340a7c098eaf464fdcec0012688fa07b0def98c9e8
|
|
7
|
+
data.tar.gz: 99828c97615dd6357dd58f167ec05338b6595cbcf5206cbad1088f9e3d3a95665f08698add77b3aeb854d4e10c9a664f8b77467ac064c680ecdd409bc763e96f
|
data/.rubocop.yml
CHANGED
|
@@ -57,3 +57,8 @@ Layout/LineLength:
|
|
|
57
57
|
# lines per site, so the cop is declined and the rule held in review.
|
|
58
58
|
Style/MethodCallWithArgsParentheses:
|
|
59
59
|
Enabled: false
|
|
60
|
+
|
|
61
|
+
# The vocabulary names a keyword for every platform, and one a platform has no field for is
|
|
62
|
+
# taken and dropped rather than left out of the signature
|
|
63
|
+
Lint/UnusedMethodArgument:
|
|
64
|
+
AllowUnusedKeywordArguments: true
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,142 @@
|
|
|
1
|
+
## [Unreleased]
|
|
2
|
+
|
|
3
|
+
## [5.0.0] - 2026-09-15
|
|
4
|
+
|
|
5
|
+
- [Feature] A scope the app was never granted no longer raises. Jobber answers `An object of
|
|
6
|
+
type User was hidden due to permissions` and hides the object rather than the query, so
|
|
7
|
+
whatever came back beside it is kept: `account.technicians` answers `[]`, and a week asked
|
|
8
|
+
for with `includes(:technicians)` answers the week with nobody on it. `Jbr.logger` takes the
|
|
9
|
+
line saying which type to tick the scope for -- standard error until an app points it
|
|
10
|
+
somewhere better. Jobber codes this refusal not at all, so the words are the only signal, and
|
|
11
|
+
only those words are carried on from: anything else raises, an empty list being a poor place
|
|
12
|
+
to hide a fault.
|
|
13
|
+
|
|
14
|
+
- [Breaking change] `account.visits.find` is gone. A visit arrives from the walk carrying
|
|
15
|
+
everything it reads, so looking one up again was a request spent to learn nothing -- and it
|
|
16
|
+
answered a job's stop alone, quietly finding nothing for an assessment, an event or a task.
|
|
17
|
+
`Enumerable#find` is what the name means on a list of visits now.
|
|
18
|
+
|
|
19
|
+
- [Feature] `visit.location`, where a stop is, through `includes(:location)`. Jobber hangs the
|
|
20
|
+
property off each kind of scheduled item rather than off what they share, so it is selected
|
|
21
|
+
inside the fragments; a caller reading a schedule no longer reaches through `visit.job` for an
|
|
22
|
+
address, which a stop booked against a lead never had.
|
|
23
|
+
|
|
24
|
+
- [Fix] A window asks for unassigned work and not for unscheduled. `schedulingAspects: [ALL]`
|
|
25
|
+
means both, so a windowed list came back carrying requests nobody had booked -- no start, no
|
|
26
|
+
end, in no window. `includeUnassigned: true` with `includeUnscheduled: false` asks for exactly
|
|
27
|
+
the half that is booked, verified against an account holding plenty of each.
|
|
28
|
+
|
|
29
|
+
- [Breaking change] An event or a task is a visit. They occupy a pro exactly as a job's stop does
|
|
30
|
+
and were being read past unread. Jobber's scheduled item has exactly four kinds -- visit,
|
|
31
|
+
assessment, event, task -- so nothing is filtered out now; a reminder is named by the filter's
|
|
32
|
+
enum but is not a scheduled item and cannot come back. `visit.job` and `visit.lead` are nil on
|
|
33
|
+
an event, and `visit.location` may be: Jobber gives an event a property, and not always.
|
|
34
|
+
|
|
35
|
+
- [Breaking change] The vocabulary is `company` 2.1: a `Company::Selection` takes its rule as a
|
|
36
|
+
block, a visit answers a lead as well as a job, and it says where it is. The pin is `~> 2.1`.
|
|
37
|
+
|
|
38
|
+
- [Feature] The README says which Developer Center object each reader needs ticked. Jobber
|
|
39
|
+
files a visit under Scheduled Items -- one object covering visits, assessments, tasks and
|
|
40
|
+
calendar events -- and there is no Visits scope of its own.
|
|
41
|
+
|
|
42
|
+
- [Feature] `account.visits.create` books a stop to go and look at work nobody has priced. It
|
|
43
|
+
takes the words `leads.create` takes plus `starts_at:`, `ends_at:` and `technicians:`, opens
|
|
44
|
+
the client and the property where Jobber has none, and files all of it in the one
|
|
45
|
+
`requestCreate`: Jobber hangs the assessment off the request it opens with it. What comes
|
|
46
|
+
back is the assessment Jobber stored, naming the request as its lead. Jobber has no source
|
|
47
|
+
for a request, so `source:` is dropped, and `ends_at:` may be nil for a stop booked to a day.
|
|
48
|
+
|
|
49
|
+
A mocked booking refuses a bare `Time` the same way, so a suite cannot pass on one Jobber
|
|
50
|
+
would not take. `starts_at:` must know its zone. Jobber takes a date, a local time and the zone they are in,
|
|
51
|
+
not a moment in UTC, and a bare `Time` names an offset rather than a zone -- so one is
|
|
52
|
+
refused, with `Jbr::Error`, before a client is opened.
|
|
53
|
+
|
|
54
|
+
- [Breaking change] `account.visits` is every stop booked, not only a job's. Jobber calls the
|
|
55
|
+
stop booked to look at work before there is a job an assessment and hangs it off the request,
|
|
56
|
+
so `visit.lead` answers that request and `visit.job` is nil there; `for_jobs` and `for_leads`
|
|
57
|
+
narrow to one kind, by Jobber rather than here. The list is read from `scheduledItems` rather
|
|
58
|
+
than `visits`, which has three consequences worth reading twice:
|
|
59
|
+
|
|
60
|
+
- **A schedule is read by the window.** `scheduledItems` takes a required `occursWithin`, so
|
|
61
|
+
`account.visits` with nothing narrowing it raises `Jbr::Error` where it used to walk every
|
|
62
|
+
visit there was.
|
|
63
|
+
- **An open end reaches a year.** `occursWithin` takes two moments and no nil, so
|
|
64
|
+
`upcoming` and `past` with no duration are bounded at a year rather than left open.
|
|
65
|
+
- **Unassigned work is in.** `scheduledItems` answers assigned work only unless told
|
|
66
|
+
otherwise, so `includeUnassigned: true` is always sent. A list that did not send it would
|
|
67
|
+
quietly drop every stop nobody is on yet.
|
|
68
|
+
|
|
69
|
+
`account.visits.find` still answers a stop of a job alone: Jobber files an assessment under a
|
|
70
|
+
lookup of its own and this gem does not reach for it. Events, tasks and reminders share the
|
|
71
|
+
list and are read past, Jobber's filter taking one kind and not two.
|
|
72
|
+
|
|
73
|
+
- [Feature] `account.technicians` walks the account's users a page at a time, each a
|
|
74
|
+
`Jbr::Technician` reading `id`, `name` and `surname` off the `name` node Jobber answers a
|
|
75
|
+
user with. Reading one needs the Users scope, which an app granted before this
|
|
76
|
+
release does not have: Jobber refuses a query selecting a user outright rather than leaving
|
|
77
|
+
the field empty, so an app that asks for a technician re-authorizes first.
|
|
78
|
+
|
|
79
|
+
- [Feature] `visit.technicians` is whoever a visit is booked for, and `includes(:technicians)`
|
|
80
|
+
is what asks for them -- nothing brings them back unbidden, for the scope above and because
|
|
81
|
+
Jobber prices them on every row that carries them.
|
|
82
|
+
|
|
83
|
+
- [Feature] `account.visits.between(from, to).assigned_to(technician)` is one technician's
|
|
84
|
+
week. `VisitFilterAttributes` takes an `assignedTo`, so the technician joins the window in
|
|
85
|
+
the one filter Jobber is sent: nobody else's visits are answered, paged or paid for, and the
|
|
86
|
+
crew is not read unless `includes(:technicians)` asks, which means `assigned_to` needs no
|
|
87
|
+
Users scope. Both narrowings land in the same filter, so either order asks the same
|
|
88
|
+
thing. `Jbr.mock.technicians` mocks the crew, and a mocked visit takes a `technicians:` of
|
|
89
|
+
its own.
|
|
90
|
+
|
|
91
|
+
## [4.0.0] - 2026-09-09
|
|
92
|
+
|
|
93
|
+
- [Breaking change] `Jbr::Account` is the gateway, and reads in the vocabulary the `company` gem
|
|
94
|
+
names. It replaces `Jbr::OAuth` and the `Jbr.oauth_for`, `Jbr.create_oauth` and
|
|
95
|
+
`Jbr.oauth_url_for` entry points: `Jbr::Account.new credentials`, `Jbr::Account.create code:,
|
|
96
|
+
redirect_uri:`, `Jbr::Account.url_for redirect_uri:, state:`, and `Jbr::Account.client_secret`.
|
|
97
|
+
`#account` is `#business`, answering a `Company::Business` whose `phone` is the ten digits to
|
|
98
|
+
dial rather than the string Jobber holds
|
|
99
|
+
- [Breaking change] `#requests` is `#leads`, and `leads.create` takes its keywords by name
|
|
100
|
+
as the vocabulary names them (`name:`, `surname:`, `phone:`, `email:`, `address:`,
|
|
101
|
+
`description:` for the title, `notes:` for the instructions, and a `source:` Jobber has no
|
|
102
|
+
field for) and
|
|
103
|
+
answers a `Jbr::Lead` with `id` and `customer` rather than the collection that filed it.
|
|
104
|
+
`Quote#request_id` is `#lead`, a `Jbr::Lead`; `Invoice#job_id` is `#job`, a `Jbr::Job`;
|
|
105
|
+
`Invoice#total`, `#issued_at` and `#completed_at` are `#amount`, a `BigDecimal`, and
|
|
106
|
+
`#fulfilled_at`, the moment the work was finished or the bill issued where the work never was
|
|
107
|
+
- [Breaking change] A job reads `#amount` as a `BigDecimal` where it read `#total` as a Float,
|
|
108
|
+
answers the quote it was won with as `#quote` -- a `Jbr::Quote` with `id` and `amount`,
|
|
109
|
+
nil where there was none -- in place of `#quote_id` and `#quote_total`, its title as
|
|
110
|
+
`#description` and its instructions as `#notes`. `#summary` is gone with `#name`: a caller sums a job up from its lines and
|
|
111
|
+
its description. `Job#title`, `#status` and `#client`, `Visit#title`, `#name`, `#job_id`
|
|
112
|
+
and `#client`, are gone, and `Visit#client_confirmed?` is `#confirmed?`, `#all_day?` is `#anytime?`
|
|
113
|
+
- [Breaking change] `includes` takes `:lines`, `:location` and `location: :customer` where it
|
|
114
|
+
took `:line_items`, `:property`, `:client` and `property: :client`, and only on jobs: a visit
|
|
115
|
+
happens where its job does, so it answers `#job` and no `#location` or `includes` of its own. A
|
|
116
|
+
job answers `#lines` and `#location`, and a location `#customer`. `Location#address` and `#state` are gone,
|
|
117
|
+
as are `Customer#first_name` and `#company_name`: `#name` answers the first name, or the
|
|
118
|
+
business's name where a person has none. `Jbr::LineItem`, `Jbr::Property`, `Jbr::Client` and
|
|
119
|
+
`Jbr::Request` are `Jbr::Line`, `Jbr::Location`, `Jbr::Customer` and `Jbr::Lead`
|
|
120
|
+
- [Breaking change] `Jbr.mock` takes `business` and `lead` where it took `account` and `request`,
|
|
121
|
+
and every slot reads by the vocabulary's keys: `description`, `amount`, `quote`,
|
|
122
|
+
`lines`, `location`, `customer`, `confirmed`, `lead`, `job`. A mock collection
|
|
123
|
+
answers the vocabulary's own kinds built from those hashes, so `Jbr::Mock::Job` and its
|
|
124
|
+
siblings are gone; `Jbr.mock = nil` hands the accounts back to Jobber
|
|
125
|
+
- [Breaking change] `Jbr::Retriable` is `Jbr::Throttled`, a `Company::Throttled` rather than a
|
|
126
|
+
`Jbr::Error`, so one rescue retries a refusal for rate from any platform; its `#cost`,
|
|
127
|
+
`#available`, `#maximum` and `#restore_rate` are gone and the numbers stay in the message.
|
|
128
|
+
`Jbr::Error` descends from `Company::Error`
|
|
129
|
+
- [Fix] An `includes` chained after `past` or `upcoming` keeps the window it was asked on. It
|
|
130
|
+
used to rebuild the list without the filter, so `account.jobs.past(1.year).includes(:lines)`
|
|
131
|
+
walked every job the account ever had
|
|
132
|
+
- [Fix] A mutation Jobber takes but will not act on raises `Jbr::Error` with the reasons Jobber
|
|
133
|
+
gave. It answers those with a 200 and the messages under the mutation's own `userErrors`,
|
|
134
|
+
which nothing read, so a client Jobber refused to open came back with a nil ID and the
|
|
135
|
+
request filed against nobody
|
|
136
|
+
- [Change] Every selection Jobber is asked for is generated from the keys the vocabulary reads
|
|
137
|
+
wherever Jobber's shape is flat, so a kind gaining a reader asks for it without a query
|
|
138
|
+
written by hand
|
|
139
|
+
|
|
1
140
|
## [3.13.0] - 2026-08-31
|
|
2
141
|
|
|
3
142
|
- [New] `Jbr::LineItem#id`, `#description` and `#amount`, beside the `#quantity` and `#name` a
|