company 2.1.0 → 3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b4dad8d6bba939008a26107865489bc6aeb9a055d8cb73e58ae7b92c012521a
4
- data.tar.gz: e0b15dbe81ec83a130beaac19d666f2d182476f20d7890f918e79d44afa8c847
3
+ metadata.gz: 49d635d99039ba1f2dd9e2fc68794b7430b49890b9ccfdacd34c420ed7d38e6d
4
+ data.tar.gz: 0d4e6da3fae824c5db9af413d5be87b94db532c336bccd1194896381eb5245cd
5
5
  SHA512:
6
- metadata.gz: 8f20e43463498126a030dc4afb64c7ed1b12c7372329e15ba222acec3217005d919f2c054e2d0da1da797e961ef725f6bbc4580a9b765eb023dc2a555e650d62
7
- data.tar.gz: 43dcfc1ecd909109e2169ba2ac419961a0cfce5a8b3bfe9c334a18569db501c9932adbb0152c427c293036721839826702a794d3064f7f3db32e65b793533bae
6
+ metadata.gz: '0524899dee91ba36a54f37ca834cd770e27a202ae3b65e79efc7aeb9bb889697184ec186724a62c015f589a51e27c866aad7ef27c8dfebc3f67b62fbd491aa86'
7
+ data.tar.gz: ff4a532ba721b64b33bab772235c17c5f3ea2bdc15622c4cd9bd4e7b3ef9d361c15862cecc9f667b4d9b84f28f8fe8f4cae6d0b2f96c7dff828c562906479028
data/CHANGELOG.md CHANGED
@@ -5,6 +5,27 @@ All notable changes to this project will be documented in this file.
5
5
  For more information about changelogs, check [Keep a Changelog](http://keepachangelog.com) and
6
6
  [Vandamme](http://tech-angels.github.io/vandamme).
7
7
 
8
+ ## 3.0.0 - 2026-09-16
9
+
10
+ - [Breaking change] `Collection#assigned_to` is `Collection#of`. It read as it should on booked
11
+ time -- a visit is assigned to somebody -- and as it should not on free time, nobody being
12
+ assigned to an hour they are not working. `account.visits.of(technician)` and
13
+ `account.windows.of(technician)` both read as the possessive they are.
14
+
15
+ - [Feature] `account.windows`, a `Company::Windows` of `Company::Window`: the free time of a
16
+ business, every stretch somebody could be sent out in, over the window asked for. A window
17
+ reads `starts_at` and `ends_at` and nothing else -- it names no work and nobody going, a list
18
+ of them having been narrowed to one technician already.
19
+
20
+ - [Feature] A window is as long as it is, rather than cut into slots of a fixed size. Only the
21
+ caller making an offer knows how long the pieces it offers need to be, and a stretch stored
22
+ whole can still be cut, where one already cut cannot be put back together.
23
+
24
+ - [Note] A platform that does not work free time out for itself raises `NotImplementedError`
25
+ from `windows`, and `Company::Windows#of` does the same, rather than answering with none. An
26
+ empty week and a fully booked one are the same shape, so a caller reading none as none would
27
+ quietly stop offering that business at all -- with nothing in a log and no page looking wrong.
28
+
8
29
  ## 2.1.0 - 2026-09-15
9
30
 
10
31
  * [Feature] `Company::Collection#includes(*names)`, what to bring back beside each record. A
data/README.md CHANGED
@@ -100,9 +100,13 @@ technician.id # => 't1'
100
100
  technician.name # => 'Grace'
101
101
  technician.surname # => 'Hopper'
102
102
 
103
- week = account.visits.between(monday, sunday).assigned_to(technician)
103
+ week = account.visits.between(monday, sunday).of(technician)
104
104
  week.ids # => ['v1', 'v2', ...]
105
105
 
106
+ free = account.windows.between(monday, sunday).of(technician)
107
+ free.first.starts_at # => 2026-09-16 13:00:00 UTC
108
+ free.first.ends_at # => 2026-09-16 17:00:00 UTC
109
+
106
110
  lead = account.leads.create name: 'Jane', surname: 'Qi', phone: '5555555666',
107
111
  email: 'jane@example.com', address: { street: '100 Acme Circle', zip: '98920' },
108
112
  description: 'Repair', notes: 'Estimate $20–$30', source: 'Website'
@@ -126,6 +130,15 @@ priced yet -- Jobber calls it an assessment, Housecall Pro an estimate -- names
126
130
  the same. `quote` stays the price, which is the other half of what Housecall Pro files as one
127
131
  record.
128
132
 
133
+ A window is the other half of the same question: not the hours somebody is out, but the ones
134
+ they are not. It names no work and nobody going, a list of them having been narrowed to one
135
+ technician already, and it is as long as it is -- cut it into offerable pieces where an offer is
136
+ being made, since only the caller making one knows how long it needs them to be.
137
+
138
+ A platform that does not work free time out for itself answers `windows` with
139
+ `NotImplementedError` rather than with none. An empty week and a fully booked one are the same
140
+ shape, so a caller reading none as none would quietly stop offering that business at all.
141
+
129
142
  ## Answering as a gem
130
143
 
131
144
  A gem subclasses `Company::Account` and answers the readers its platform offers, and subclasses
@@ -151,7 +164,7 @@ end
151
164
  the platform for. A reader the gem leaves out raises `NotImplementedError` naming the gem; leads
152
165
  it leaves out refuse to file one, and so do the visits. `includes` a gem leaves out answers the
153
166
  same list: a platform that hands a record over whole has nothing to bring back beside it, so a
154
- caller names what it reads without knowing which kind of platform it is talking to. `assigned_to`,
167
+ caller names what it reads without knowing which kind of platform it is talking to. `of`,
155
168
  `for_jobs` and `for_leads` a gem leaves out still answer: `Company::Selection` walks the list and lets through
156
169
  what the rule keeps, so only a platform that can put the question to its server writes the
157
170
  method, and only to save the requests the walk would spend. The least a gem writes is under `test/acme`, and the test that
@@ -15,6 +15,9 @@ module Company
15
15
  # @return [Collection] technicians of the business, each a {Technician}.
16
16
  def technicians = unanswered :technicians
17
17
 
18
+ # @return [Windows] free time of the business, each a {Window}, where the platform works it out.
19
+ def windows = unanswered :windows
20
+
18
21
  # @return [Leads] leads of the business: `create` files one, where the platform takes leads.
19
22
  def leads = Leads.new
20
23
 
@@ -30,8 +30,8 @@ module Company
30
30
  # A platform that can ask its server for one technician's work narrows the list there; one
31
31
  # that cannot walks the list and keeps what the technician turns out to be on.
32
32
  # @param technician [Technician] whoever the work is booked for.
33
- # @return [Collection] the same list, narrowed to what they are assigned to.
34
- def assigned_to(technician)
33
+ # @return [Collection] the same list, narrowed to theirs.
34
+ def of(technician)
35
35
  Selection.new(collection: self) do |record|
36
36
  record.technicians.any? { |each| each.id == technician.id }
37
37
  end
@@ -0,0 +1,16 @@
1
+ module Company
2
+ # The free time of a business: every stretch somebody could be sent out in, over the window
3
+ # asked for. A platform that works it out answers this; one that does not know when its
4
+ # business is open cannot, and says so rather than answering with none, an empty list being
5
+ # the same shape as a fully booked week.
6
+ class Windows < Collection
7
+ # A window names nobody, a list of them having been narrowed to one technician already, so
8
+ # there is nothing here to walk and keep: only the platform can tell one person's free time
9
+ # from another's.
10
+ # @param technician [Technician] whose free time to answer.
11
+ # @return [Windows] the same list, as that technician's alone.
12
+ def of(technician)
13
+ raise NotImplementedError, "#{self.class} does not answer one technician's windows"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Company
2
+ # Free time: a stretch nobody is booked for, which somebody could be sent out in. It names no
3
+ # work and nobody going, a list of them having been asked for one technician already, and it
4
+ # is as long as it is -- cut it into offerable pieces where an offer is being made, since only
5
+ # the caller making one knows how long it needs them to be.
6
+ class Window < Resource
7
+ # What every window reads, by the vocabulary's names.
8
+ def self.attributes = %i[starts_at ends_at]
9
+
10
+ # @return [Time] moment the free stretch opens.
11
+ def starts_at = time :starts_at
12
+
13
+ # @return [Time] moment the free stretch closes.
14
+ def ends_at = time :ends_at
15
+ end
16
+ end
@@ -1,5 +1,5 @@
1
1
  # The vocabulary two platform gems share: an account opens a business and the records it holds.
2
2
  module Company
3
3
  # The version of this gem, as RubyGems knows it.
4
- VERSION = '2.1.0'
4
+ VERSION = '3.0.0'
5
5
  end
data/lib/company.rb CHANGED
@@ -20,6 +20,7 @@ require 'company/collection'
20
20
  require 'company/selection'
21
21
  require 'company/collections/leads'
22
22
  require 'company/collections/visits'
23
+ require 'company/collections/windows'
23
24
  require 'company/account'
24
25
  require 'company/resources/business'
25
26
  require 'company/resources/customer'
@@ -29,4 +30,5 @@ require 'company/resources/line'
29
30
  require 'company/resources/lead'
30
31
  require 'company/resources/quote'
31
32
  require 'company/resources/visit'
33
+ require 'company/resources/window'
32
34
  require 'company/resources/job'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: company
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Claudio Baccigalupo
@@ -39,6 +39,7 @@ files:
39
39
  - lib/company/collection.rb
40
40
  - lib/company/collections/leads.rb
41
41
  - lib/company/collections/visits.rb
42
+ - lib/company/collections/windows.rb
42
43
  - lib/company/error.rb
43
44
  - lib/company/errors/throttled.rb
44
45
  - lib/company/phone.rb
@@ -52,6 +53,7 @@ files:
52
53
  - lib/company/resources/quote.rb
53
54
  - lib/company/resources/technician.rb
54
55
  - lib/company/resources/visit.rb
56
+ - lib/company/resources/window.rb
55
57
  - lib/company/selection.rb
56
58
  - lib/company/version.rb
57
59
  homepage: https://github.com/claudiob/company