patch_retention 0.2.2 → 0.3.2
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/CHANGELOG.md +26 -0
- data/Gemfile.lock +1 -1
- data/README.md +99 -0
- data/lib/patch_retention/calendar_items.rb +86 -0
- data/lib/patch_retention/contacts/find.rb +4 -1
- data/lib/patch_retention/contacts.rb +2 -2
- data/lib/patch_retention/memberships.rb +3 -2
- data/lib/patch_retention/version.rb +1 -1
- metadata +19 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 109e3aa27d410ae2245f0b1de8a71a1531951869ff99e1c122e406c172e41c5b
|
4
|
+
data.tar.gz: 6666fdc1241ae1bb07fe9e5a014fd6f8c4950c9e9521ebb1c4d1e036c9135f03
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 747343cd474efbbf2e881bf9921cc0b9c4166821a96f2fcf69edcc8effee88481b0f80bcfae9921b631fb66a72df39d2934e4f69424df7c2352d4f2faaf5a28f
|
7
|
+
data.tar.gz: 18b13644f200d75450d070b085a054d02da6aab70d51981cce43126371d50dfe2eefc2c42bf2caa70d9d878cdcc15e18f9337dc7d721d5f1b4c85b6bc0e1ba3e
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,31 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.3.2] - 2025-01-19
|
4
|
+
|
5
|
+
### Added
|
6
|
+
- Added `next_billing_at` field support to `Memberships.create` method for setting the next billing date
|
7
|
+
|
8
|
+
## [0.3.1] - 2025-09-04
|
9
|
+
|
10
|
+
### Added
|
11
|
+
- Added `tags` parameter support to `CalendarItems.create` method for categorizing calendar items
|
12
|
+
- Added `email` parameter to `Contacts.all` method for filtering contacts by email address
|
13
|
+
|
14
|
+
### Changed
|
15
|
+
- **BREAKING**: Updated `Contacts.all` method to use keyword arguments (limit:, offset:, email:, config:) instead of positional arguments
|
16
|
+
|
17
|
+
## [0.3.0] - 2025-07-27
|
18
|
+
|
19
|
+
### Added
|
20
|
+
- Calendar Items API support with full CRUD operations:
|
21
|
+
- `create` - Create calendar events for contacts
|
22
|
+
- `update` - Update existing calendar items
|
23
|
+
- `find` - Retrieve a specific calendar item
|
24
|
+
- `delete` - Remove calendar items
|
25
|
+
- `all` - List calendar items with filtering and pagination support
|
26
|
+
- Support for calendar item metadata including description, location, external_id, external_data, and tags
|
27
|
+
- Comprehensive test coverage for Calendar Items functionality
|
28
|
+
|
3
29
|
## [0.2.0] - 2025-05-26
|
4
30
|
|
5
31
|
### Added
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -118,7 +118,21 @@ Then, you can use the gem's methods to interact with the API.
|
|
118
118
|
To retrieve all contacts:
|
119
119
|
|
120
120
|
```ruby
|
121
|
+
# Basic usage
|
121
122
|
contacts = PatchRetention::Contacts.all
|
123
|
+
|
124
|
+
# With pagination (using keyword arguments)
|
125
|
+
contacts = PatchRetention::Contacts.all(limit: 10, offset: 0)
|
126
|
+
|
127
|
+
# With email filter
|
128
|
+
contacts = PatchRetention::Contacts.all(email: 'john.doe@example.com')
|
129
|
+
|
130
|
+
# With pagination and email filter
|
131
|
+
contacts = PatchRetention::Contacts.all(
|
132
|
+
limit: 50,
|
133
|
+
offset: 0,
|
134
|
+
email: 'john@example.com'
|
135
|
+
)
|
122
136
|
```
|
123
137
|
|
124
138
|
To retrieve a single contact:
|
@@ -264,6 +278,7 @@ membership = PatchRetention::Memberships.create(
|
|
264
278
|
product_id: "65de5xxxxxxxxxxxxx", # Required, ID of the product (e.g., from product creation)
|
265
279
|
start_at: Time.now.xmlschema, # Optional, ISO8601 timestamp
|
266
280
|
end_at: (Time.now + 30*24*60*60).xmlschema, # Optional, ISO8601 timestamp (e.g., 30 days from now)
|
281
|
+
next_billing_at: (Time.now + 7*24*60*60).xmlschema, # Optional, ISO8601 timestamp for next billing date
|
267
282
|
external_id: "MEM123", # Optional
|
268
283
|
data: {
|
269
284
|
"is_trial" => true,
|
@@ -290,6 +305,90 @@ To find a membership:
|
|
290
305
|
membership = PatchRetention::Memberships.find(membership_id: "mem_xxxxxxxxxxxxxx")
|
291
306
|
```
|
292
307
|
|
308
|
+
**Calendar Items**
|
309
|
+
|
310
|
+
To create a calendar item:
|
311
|
+
|
312
|
+
```ruby
|
313
|
+
calendar_item = PatchRetention::CalendarItems.create(
|
314
|
+
contact_id: "ct_xxxxxxxxxxxxxx", # Required, ID of the contact
|
315
|
+
title: "Tennis Court Reservation", # Required, title of the event
|
316
|
+
start_at: "2025-02-01T10:00:00Z", # Required, ISO8601 timestamp - when the event starts
|
317
|
+
end_at: "2025-02-01T11:00:00Z", # Required, ISO8601 timestamp - when the event ends
|
318
|
+
run_start_at: "2025-02-01T09:30:00Z", # Optional, ISO8601 - when to run the event for this item (defaults to start_at if not set)
|
319
|
+
run_end_at: "2025-02-01T11:30:00Z", # Optional, ISO8601 - when to run the event for this item (defaults to end_at if not set)
|
320
|
+
data: { # Optional, additional metadata that will be included in the calendar item
|
321
|
+
external_id: "res_123456", # Your system's ID
|
322
|
+
facility_id: "fac_789",
|
323
|
+
court_name: "Court 1",
|
324
|
+
reservation_type: "match"
|
325
|
+
},
|
326
|
+
tags: ["tennis", "premium", "court1"], # Optional, array of tags to categorize the calendar item
|
327
|
+
time_occurred: "2025-01-28T09:00:00Z", # Optional, ISO8601 - past or current time for the event (will default to now)
|
328
|
+
skip_triggers: false # Optional, if set to false or empty, any automation tied to the calendar item will not run
|
329
|
+
)
|
330
|
+
# => {"id"=>"cal_xxxxxxxxxxxxxx", "contact_id"=>"ct_xxxxxxxxxxxxxx", ...}
|
331
|
+
```
|
332
|
+
|
333
|
+
To update a calendar item:
|
334
|
+
|
335
|
+
```ruby
|
336
|
+
calendar_item = PatchRetention::CalendarItems.update(
|
337
|
+
calendar_item_id: "cal_xxxxxxxxxxxxxx",
|
338
|
+
title: "Updated Tennis Match",
|
339
|
+
end_at: "2025-02-01T12:00:00Z", # Extend by 1 hour
|
340
|
+
data: {
|
341
|
+
description: "Match extended due to tie-break"
|
342
|
+
},
|
343
|
+
tags: ["Tennis", "Extended", "Tie-break"] # Tags as separate parameter
|
344
|
+
)
|
345
|
+
```
|
346
|
+
|
347
|
+
To find a calendar item:
|
348
|
+
|
349
|
+
```ruby
|
350
|
+
calendar_item = PatchRetention::CalendarItems.find(calendar_item_id: "cal_xxxxxxxxxxxxxx")
|
351
|
+
```
|
352
|
+
|
353
|
+
To delete a calendar item:
|
354
|
+
|
355
|
+
```ruby
|
356
|
+
result = PatchRetention::CalendarItems.delete(calendar_item_id: "cal_xxxxxxxxxxxxxx")
|
357
|
+
# => { success: true }
|
358
|
+
```
|
359
|
+
|
360
|
+
To list calendar items:
|
361
|
+
|
362
|
+
```ruby
|
363
|
+
# List all calendar items
|
364
|
+
calendar_items = PatchRetention::CalendarItems.all()
|
365
|
+
|
366
|
+
# List calendar items for a specific contact
|
367
|
+
calendar_items = PatchRetention::CalendarItems.all(contact_id: "ct_xxxxxxxxxxxxxx")
|
368
|
+
|
369
|
+
# List calendar items within ID range (MongoDB IDs)
|
370
|
+
calendar_items = PatchRetention::CalendarItems.all(
|
371
|
+
min_id: "0123456789abcdefghijklmn", # Get all items on or after this ID
|
372
|
+
max_id: "0123456789abcdefghijklmn" # Get all items on or before this ID
|
373
|
+
)
|
374
|
+
|
375
|
+
# List specific calendar items by IDs (comma-separated)
|
376
|
+
calendar_items = PatchRetention::CalendarItems.all(
|
377
|
+
id: "0123456789abcdefghijklmn,123456789abcdefghijklmn"
|
378
|
+
)
|
379
|
+
|
380
|
+
# Filter by date range (predefined options)
|
381
|
+
calendar_items = PatchRetention::CalendarItems.all(
|
382
|
+
date_range: "Today" # Options: "Today", "Yesterday", "Last 7 Days", "This Week", "Last Week", "Last 30 Days"
|
383
|
+
)
|
384
|
+
|
385
|
+
# With pagination
|
386
|
+
calendar_items = PatchRetention::CalendarItems.all(
|
387
|
+
limit: 50, # Default is 50, max is 100
|
388
|
+
offset: 25 # Skip first 25 results
|
389
|
+
)
|
390
|
+
```
|
391
|
+
|
293
392
|
## Development
|
294
393
|
|
295
394
|
After checking out the repo, run `bin/setup` to install dependencies.
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PatchRetention
|
4
|
+
class CalendarItems
|
5
|
+
class << self
|
6
|
+
def create(contact_id:, title:, start_at:, end_at:, run_start_at: nil, run_end_at: nil,
|
7
|
+
data: nil, time_occurred: nil, skip_triggers: false, tags: nil, config: nil)
|
8
|
+
payload = {
|
9
|
+
contact_id: contact_id,
|
10
|
+
title: title,
|
11
|
+
start_at: start_at,
|
12
|
+
end_at: end_at,
|
13
|
+
}
|
14
|
+
payload[:run_start_at] = run_start_at if run_start_at
|
15
|
+
payload[:run_end_at] = run_end_at if run_end_at
|
16
|
+
payload[:data] = data if data
|
17
|
+
payload[:time_occurred] = time_occurred if time_occurred
|
18
|
+
payload[:skip_triggers] = skip_triggers unless skip_triggers.nil?
|
19
|
+
payload[:tags] = tags if tags
|
20
|
+
|
21
|
+
response = PatchRetention.connection(config).post("/v2/calendar_items") do |req|
|
22
|
+
req.body = payload.to_json
|
23
|
+
req.headers["Content-Type"] = "application/json"
|
24
|
+
end
|
25
|
+
|
26
|
+
JSON.parse(response.body)
|
27
|
+
rescue Faraday::Error => e
|
28
|
+
raise Error, "Failed to create calendar item: #{e.message}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def update(calendar_item_id:, title: nil, start_at: nil, end_at: nil, run_start_at: nil,
|
32
|
+
run_end_at: nil, data: nil, tags: nil, config: nil)
|
33
|
+
payload = {}
|
34
|
+
payload[:title] = title if title
|
35
|
+
payload[:start_at] = start_at if start_at
|
36
|
+
payload[:end_at] = end_at if end_at
|
37
|
+
payload[:run_start_at] = run_start_at if run_start_at
|
38
|
+
payload[:run_end_at] = run_end_at if run_end_at
|
39
|
+
payload[:data] = data if data
|
40
|
+
payload[:tags] = tags if tags
|
41
|
+
|
42
|
+
response = PatchRetention.connection(config).patch("/v2/calendar_items/#{calendar_item_id}") do |req|
|
43
|
+
req.body = payload.to_json
|
44
|
+
req.headers["Content-Type"] = "application/json"
|
45
|
+
end
|
46
|
+
|
47
|
+
JSON.parse(response.body)
|
48
|
+
rescue Faraday::Error => e
|
49
|
+
raise Error, "Failed to update calendar item: #{e.message}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def find(calendar_item_id:, config: nil)
|
53
|
+
response = PatchRetention.connection(config).get("/v2/calendar_items/#{calendar_item_id}")
|
54
|
+
|
55
|
+
JSON.parse(response.body)
|
56
|
+
rescue Faraday::Error => e
|
57
|
+
raise Error, "Failed to find calendar item: #{e.message}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete(calendar_item_id:, config: nil)
|
61
|
+
response = PatchRetention.connection(config).delete("/v2/calendar_items/#{calendar_item_id}")
|
62
|
+
|
63
|
+
{ success: response.status == 204 }
|
64
|
+
rescue Faraday::Error => e
|
65
|
+
raise Error, "Failed to delete calendar item: #{e.message}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def all(contact_id: nil, min_id: nil, max_id: nil, id: nil, date_range: nil, limit: nil, offset: nil, config: nil)
|
69
|
+
params = {}
|
70
|
+
params[:contact_id] = contact_id if contact_id
|
71
|
+
params[:min_id] = min_id if min_id
|
72
|
+
params[:max_id] = max_id if max_id
|
73
|
+
params[:id] = id if id
|
74
|
+
params[:date_range] = date_range if date_range
|
75
|
+
params[:limit] = limit if limit
|
76
|
+
params[:offset] = offset if offset
|
77
|
+
|
78
|
+
response = PatchRetention.connection(config).get("/v2/calendar_items", params)
|
79
|
+
|
80
|
+
JSON.parse(response.body)
|
81
|
+
rescue Faraday::Error => e
|
82
|
+
raise Error, "Failed to retrieve calendar items: #{e.message}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -29,13 +29,16 @@ module PatchRetention::Contacts::Find
|
|
29
29
|
#
|
30
30
|
# @param limit [Integer] The number of contacts to retrieve per page.
|
31
31
|
# @param offset [Integer] The number of contacts to skip before starting to collect the result set.
|
32
|
+
# @param email [String] Optional email to filter contacts by.
|
33
|
+
# @param config [Configuration] Optional configuration object.
|
32
34
|
# @return [Object] The response from the PatchRetention API.
|
33
35
|
# @raise [PatchRetention::Error] If the API returns a status other than 200.
|
34
|
-
def all(limit
|
36
|
+
def all(limit:, offset:, email: nil, config: nil)
|
35
37
|
raise_error_if_present do
|
36
38
|
PatchRetention.connection(config).get(PatchRetention::Contacts::API_PATH) do |req|
|
37
39
|
req.params["limit"] = limit
|
38
40
|
req.params["offset"] = offset
|
41
|
+
req.params["email"] = email if email
|
39
42
|
end
|
40
43
|
end
|
41
44
|
end
|
@@ -8,8 +8,8 @@ class PatchRetention::Contacts
|
|
8
8
|
Find.by_id(id, config)
|
9
9
|
end
|
10
10
|
|
11
|
-
def all(limit
|
12
|
-
Find.all(limit, offset, config)
|
11
|
+
def all(limit: 30, offset: 0, email: nil, config: nil)
|
12
|
+
Find.all(limit: limit, offset: offset, email: email, config: config)
|
13
13
|
end
|
14
14
|
|
15
15
|
def find_or_create_by(contact_params:, query_params: {}, config: nil)
|
@@ -3,14 +3,15 @@
|
|
3
3
|
module PatchRetention
|
4
4
|
class Memberships
|
5
5
|
class << self
|
6
|
-
def create(contact_id:, product_id:, start_at: nil, end_at: nil,
|
7
|
-
config: nil)
|
6
|
+
def create(contact_id:, product_id:, start_at: nil, end_at: nil, next_billing_at: nil, external_id: nil,
|
7
|
+
tags: nil, data: nil, config: nil)
|
8
8
|
payload = {
|
9
9
|
contact_id: contact_id,
|
10
10
|
product_id: product_id,
|
11
11
|
}
|
12
12
|
payload[:start_at] = start_at if start_at
|
13
13
|
payload[:end_at] = end_at if end_at
|
14
|
+
payload[:next_billing_at] = next_billing_at if next_billing_at
|
14
15
|
payload[:external_id] = external_id if external_id
|
15
16
|
payload[:tags] = tags if tags
|
16
17
|
payload[:data] = data if data
|
metadata
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: patch_retention
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Playbypoint
|
8
8
|
- Gerardo Ortega
|
9
|
+
- Segundo Rebaza
|
9
10
|
autorequire:
|
10
11
|
bindir: exe
|
11
12
|
cert_chain: []
|
12
|
-
date: 2025-
|
13
|
+
date: 2025-09-19 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: faraday
|
@@ -67,20 +68,6 @@ dependencies:
|
|
67
68
|
- - "~>"
|
68
69
|
- !ruby/object:Gem::Version
|
69
70
|
version: '0.9'
|
70
|
-
- !ruby/object:Gem::Dependency
|
71
|
-
name: thor
|
72
|
-
requirement: !ruby/object:Gem::Requirement
|
73
|
-
requirements:
|
74
|
-
- - ">="
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
version: 1.4.0
|
77
|
-
type: :development
|
78
|
-
prerelease: false
|
79
|
-
version_requirements: !ruby/object:Gem::Requirement
|
80
|
-
requirements:
|
81
|
-
- - ">="
|
82
|
-
- !ruby/object:Gem::Version
|
83
|
-
version: 1.4.0
|
84
71
|
- !ruby/object:Gem::Dependency
|
85
72
|
name: byebug
|
86
73
|
requirement: !ruby/object:Gem::Requirement
|
@@ -179,6 +166,20 @@ dependencies:
|
|
179
166
|
- - "~>"
|
180
167
|
- !ruby/object:Gem::Version
|
181
168
|
version: '2.15'
|
169
|
+
- !ruby/object:Gem::Dependency
|
170
|
+
name: thor
|
171
|
+
requirement: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - ">="
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: 1.4.0
|
176
|
+
type: :development
|
177
|
+
prerelease: false
|
178
|
+
version_requirements: !ruby/object:Gem::Requirement
|
179
|
+
requirements:
|
180
|
+
- - ">="
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: 1.4.0
|
182
183
|
- !ruby/object:Gem::Dependency
|
183
184
|
name: vcr
|
184
185
|
requirement: !ruby/object:Gem::Requirement
|
@@ -225,6 +226,7 @@ description: Patch Retention API wrapper.
|
|
225
226
|
email:
|
226
227
|
- webmaster@playbypoint.com
|
227
228
|
- g3ortega@gmail.com
|
229
|
+
- alvaro.rp1593@gmail.com
|
228
230
|
executables: []
|
229
231
|
extensions: []
|
230
232
|
extra_rdoc_files: []
|
@@ -251,6 +253,7 @@ files:
|
|
251
253
|
- docs/references/troubleshooting.md
|
252
254
|
- docs/wip/session-2025-05-26.md
|
253
255
|
- lib/patch_retention.rb
|
256
|
+
- lib/patch_retention/calendar_items.rb
|
254
257
|
- lib/patch_retention/configuration.rb
|
255
258
|
- lib/patch_retention/contacts.rb
|
256
259
|
- lib/patch_retention/contacts/delete.rb
|