moco-ruby 1.2.0 → 1.3.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: 7527d151ba5f10b9406932d5f6e488d73897fab49ef9ab9a89341166adde7d42
4
- data.tar.gz: ce1efd8024e78ab0541229172735ac27c8ec4595eeaf86d3183bc09d72b59504
3
+ metadata.gz: a32219e92cf0b5cc11f885486ec9a0afce63d39d2a2de95f3d5225b5521020e5
4
+ data.tar.gz: fa20563a9ff63d9b412540b99beecdab249ee7dca31608d23a47a82926062f27
5
5
  SHA512:
6
- metadata.gz: ecad34b5401422a64351c4814c262ad9328bde6cdfa096f2295ae58b5aa56aa015dbd2c06905a6c212a6efa3b13236c45df12dd8534c15861d61dbb5071630bd
7
- data.tar.gz: fe46f175939e575b1b63459a10b2ababb5137e4fae30230e59ea45185c996f6e52e9b56ecc11184a2a8fc8a7c28deda74d134594a0940cc3358d7100b4cd735b
6
+ metadata.gz: 63995cff5c2e36f43619a43e04208460d8aa3a899f06a8b4e0acc673655af550ac40f472519096a8da21d73d850705a4d4a10d788287eb6cac1a461d614c4139
7
+ data.tar.gz: 7be74a0104d6bfffd3d3bb93f6658db539ec1727e108795f69a63c1b38447d0876eb21187c0557936fa0b70d7457a4150bccd9eed3ba04e8df6f3d32c59179ef
data/.rubocop.yml CHANGED
@@ -16,6 +16,7 @@ Naming/MethodParameterName:
16
16
  - a
17
17
  - b
18
18
  - id
19
+ - to
19
20
 
20
21
  Layout/LineLength:
21
22
  Max: 130
data/CHANGELOG.md CHANGED
@@ -2,6 +2,26 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [1.3.0] - 2026-05-23
6
+
7
+ ### Added
8
+ - New entities to cover remaining MOCO API v1 resources: `LetterPaper`
9
+ (read-only letterhead listing), `InvoiceAttachment`, `OfferAttachment`,
10
+ and `Session` (API key exchange/verification).
11
+ - `MOCO::Session.create(subdomain:, email:, password:)` exchanges credentials
12
+ for an API key without requiring an existing `Client`.
13
+ - `moco.session.verify` confirms the configured API key and returns the user
14
+ identity.
15
+
16
+ ### Changed
17
+ - `Invoice#attachments` and `Offer#attachments` now return a
18
+ `NestedCollectionProxy` of typed `InvoiceAttachment` / `OfferAttachment`
19
+ entities, replacing the previous raw `add_attachment` / `delete_attachment`
20
+ helpers. Use `invoice.attachments.create(attachment: { filename:, base64: })`
21
+ and `invoice.attachments.find(id).destroy` instead.
22
+ - Documentation URLs updated from `hundertzehn.github.io/mocoapp-api-docs`
23
+ (legacy) to `docs.mocoapp.com/api/docs/v1` (current OpenAPI reference).
24
+
5
25
  ## [1.2.0] - 2026-01-14
6
26
 
7
27
  ### Added
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- moco-ruby (1.2.0)
4
+ moco-ruby (1.3.0)
5
5
  activesupport (>= 7.0)
6
6
  faraday (>= 2.0)
7
7
  fuzzy_match (~> 2.1.0)
@@ -9,7 +9,7 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- activesupport (8.1.2)
12
+ activesupport (8.1.3)
13
13
  base64
14
14
  bigdecimal
15
15
  concurrent-ruby (~> 1.0, >= 1.3.1)
@@ -22,11 +22,11 @@ GEM
22
22
  securerandom (>= 0.3)
23
23
  tzinfo (~> 2.0, >= 2.0.5)
24
24
  uri (>= 0.13.1)
25
- addressable (2.8.8)
25
+ addressable (2.9.0)
26
26
  public_suffix (>= 2.0.2, < 8.0)
27
27
  ast (2.4.3)
28
28
  base64 (0.3.0)
29
- bigdecimal (4.0.1)
29
+ bigdecimal (4.1.2)
30
30
  concurrent-ruby (1.3.6)
31
31
  connection_pool (3.0.2)
32
32
  crack (1.0.1)
@@ -34,21 +34,22 @@ GEM
34
34
  rexml
35
35
  dotenv (2.8.1)
36
36
  drb (2.2.3)
37
- faraday (2.14.0)
37
+ faraday (2.14.2)
38
38
  faraday-net_http (>= 2.0, < 3.5)
39
39
  json
40
40
  logger
41
- faraday-net_http (3.4.2)
41
+ faraday-net_http (3.4.3)
42
42
  net-http (~> 0.5)
43
43
  fuzzy_match (2.1.0)
44
44
  hashdiff (1.2.1)
45
45
  i18n (1.14.8)
46
46
  concurrent-ruby (~> 1.0)
47
- json (2.18.0)
47
+ json (2.19.5)
48
48
  language_server-protocol (3.17.0.5)
49
49
  lint_roller (1.1.0)
50
50
  logger (1.7.0)
51
- minitest (6.0.1)
51
+ minitest (6.0.6)
52
+ drb (~> 2.0)
52
53
  prism (~> 1.5)
53
54
  net-http (0.9.1)
54
55
  uri (>= 0.11.1)
@@ -57,8 +58,8 @@ GEM
57
58
  ast (~> 2.4.1)
58
59
  racc
59
60
  power_assert (3.0.1)
60
- prism (1.7.0)
61
- public_suffix (7.0.2)
61
+ prism (1.9.0)
62
+ public_suffix (7.0.5)
62
63
  racc (1.8.1)
63
64
  rainbow (3.1.1)
64
65
  rake (13.3.1)
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/moco-ruby.svg)](https://badge.fury.io/rb/moco-ruby)
4
4
 
5
- A Ruby Gem to interact with the [MOCO API](https://hundertzehn.github.io/mocoapp-api-docs/). This gem provides a modern, Ruby-esque interface (`MOCO::Client`) for interacting with the MOCO API.
5
+ A Ruby Gem to interact with the [MOCO API](https://docs.mocoapp.com/api/docs/v1). This gem provides a modern, Ruby-esque interface (`MOCO::Client`) for interacting with the MOCO API.
6
6
 
7
7
  ## Installation
8
8
 
@@ -176,6 +176,47 @@ profile = moco.profile
176
176
  puts "Logged in as: #{profile.firstname} #{profile.lastname}"
177
177
  ```
178
178
 
179
+ ### Sessions
180
+
181
+ Exchange email/password for an API key, or verify an existing key:
182
+
183
+ ```ruby
184
+ # Exchange credentials for an API key (no Client needed)
185
+ session = MOCO::Session.create(
186
+ subdomain: "your-subdomain",
187
+ email: "you@example.com",
188
+ password: "secret"
189
+ )
190
+ api_key = session["api_key"]
191
+
192
+ # Verify the configured API key for an existing client
193
+ identity = moco.session.verify
194
+ puts "Authenticated as user #{identity['id']} (#{identity['uuid']})"
195
+ ```
196
+
197
+ ### Invoice / Offer Attachments
198
+
199
+ Attachments are nested under the parent document and use base64-encoded uploads:
200
+
201
+ ```ruby
202
+ require "base64"
203
+
204
+ invoice = moco.invoices.find(123)
205
+ invoice.attachments.all
206
+ invoice.attachments.create(
207
+ attachment: {
208
+ filename: "appendix.pdf",
209
+ base64: Base64.strict_encode64(File.read("appendix.pdf"))
210
+ }
211
+ )
212
+ invoice.attachments.find(42).destroy
213
+
214
+ # Offer attachments work the same way:
215
+ moco.offers.find(123).attachments.create(
216
+ attachment: { filename: "quote-details.pdf", base64: ... }
217
+ )
218
+ ```
219
+
179
220
  ### Reports
180
221
 
181
222
  Access read-only report endpoints:
@@ -212,9 +253,12 @@ The gem supports all MOCO API entities with a Ruby-esque interface:
212
253
  `InvoiceBookkeepingExport`, `PurchaseBookkeepingExport`
213
254
 
214
255
  **Nested Resources:**
215
- `Employment`, `WorkTimeAdjustment`, `ProjectContract`, `PaymentSchedule`, `RecurringExpense`, `InvoicePayment`, `InvoiceReminder`, `OfferApproval`
256
+ `Employment`, `WorkTimeAdjustment`, `ProjectContract`, `PaymentSchedule`, `RecurringExpense`, `InvoicePayment`, `InvoiceReminder`, `OfferApproval`, `InvoiceAttachment`, `OfferAttachment`
257
+
258
+ **Misc:**
259
+ `LetterPaper` (read-only), `Session` (for API key exchange/verification)
216
260
 
217
- Access them via the client using their plural, snake_case names (e.g., `moco.planning_entries`, `moco.vat_code_sales`).
261
+ Access them via the client using their plural, snake_case names (e.g., `moco.planning_entries`, `moco.vat_code_sales`, `moco.letter_papers`). Attachments are accessed via the parent: `invoice.attachments`, `offer.attachments`.
218
262
 
219
263
  ## Utilities
220
264
 
data/lib/moco/client.rb CHANGED
@@ -42,6 +42,13 @@ module MOCO
42
42
  Profile.new(self, get("profile"))
43
43
  end
44
44
 
45
+ # Session helper for verifying the configured API key.
46
+ # Use MOCO::Session.create(subdomain:, email:, password:) to exchange
47
+ # credentials for an API key without a Client.
48
+ def session
49
+ @session ||= Session.new(self)
50
+ end
51
+
45
52
  # Reports namespace for read-only report endpoints
46
53
  def reports
47
54
  @reports ||= ReportsProxy.new(self)
@@ -90,21 +90,10 @@ module MOCO
90
90
  self
91
91
  end
92
92
 
93
- # Get attachments for this invoice
93
+ # Fetches attachments for this invoice as a NestedCollectionProxy.
94
+ # Supports .all, .find(id), .create(attachment: { filename:, base64: }), and .destroy.
94
95
  def attachments
95
- client.get("invoices/#{id}/attachments")
96
- end
97
-
98
- # Add an attachment to the invoice
99
- def add_attachment(file_data)
100
- client.post("invoices/#{id}/attachments", file_data)
101
- self
102
- end
103
-
104
- # Delete an attachment from the invoice
105
- def delete_attachment(attachment_id)
106
- client.delete("invoices/#{id}/attachments/#{attachment_id}")
107
- self
96
+ MOCO::NestedCollectionProxy.new(client, self, :attachments, "InvoiceAttachment")
108
97
  end
109
98
 
110
99
  # Fetches payments for this invoice
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MOCO
4
+ # Represents an attachment on a MOCO invoice
5
+ #
6
+ # == Required attributes for create:
7
+ # attachment - Hash with the following keys:
8
+ # filename - String, file name including extension (e.g., "appendix.pdf")
9
+ # base64 - String, base64-encoded file content
10
+ #
11
+ # == Read-only attributes:
12
+ # id, title, created_at, updated_at
13
+ #
14
+ # == Usage:
15
+ # invoice = moco.invoices.find(123)
16
+ # invoice.attachments.all
17
+ # invoice.attachments.create(
18
+ # attachment: {
19
+ # filename: "appendix.pdf",
20
+ # base64: Base64.strict_encode64(File.read("appendix.pdf"))
21
+ # }
22
+ # )
23
+ # invoice.attachments.find(42).destroy
24
+ #
25
+ # == Note:
26
+ # The API only supports list (GET), create (POST), and delete (DELETE).
27
+ # Update is not available - delete and re-upload to replace.
28
+ #
29
+ class InvoiceAttachment < BaseEntity
30
+ def to_s
31
+ title.to_s
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MOCO
4
+ # Represents a MOCO letter paper (letterhead template used on invoices/offers PDFs)
5
+ # Read-only listing of letterheads configured in the MOCO account.
6
+ #
7
+ # == Read-only attributes:
8
+ # id, name, active, template, file, created_at, updated_at
9
+ #
10
+ # == Usage:
11
+ # moco.letter_papers.all
12
+ #
13
+ # == Note:
14
+ # The API only exposes a list endpoint (GET /letter_papers).
15
+ # Use a letter paper's `id` as `letter_paper_id` when fetching
16
+ # invoice/offer PDFs (e.g. GET /invoices/{id}.pdf?letter_paper_id=...).
17
+ #
18
+ class LetterPaper < BaseEntity
19
+ def to_s
20
+ name.to_s
21
+ end
22
+ end
23
+ end
@@ -85,21 +85,10 @@ module MOCO
85
85
  reload
86
86
  end
87
87
 
88
- # Get attachments for this offer
88
+ # Fetches attachments for this offer as a NestedCollectionProxy.
89
+ # Supports .all, .find(id), .create(attachment: { filename:, base64: }), and .destroy.
89
90
  def attachments
90
- client.get("offers/#{id}/attachments")
91
- end
92
-
93
- # Add an attachment to the offer
94
- def add_attachment(file_data)
95
- client.post("offers/#{id}/attachments", file_data)
96
- self
97
- end
98
-
99
- # Delete an attachment from the offer
100
- def delete_attachment(attachment_id)
101
- client.delete("offers/#{id}/attachments/#{attachment_id}")
102
- self
91
+ MOCO::NestedCollectionProxy.new(client, self, :attachments, "OfferAttachment")
103
92
  end
104
93
 
105
94
  # Associations
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MOCO
4
+ # Represents an attachment on a MOCO offer
5
+ #
6
+ # == Required attributes for create:
7
+ # attachment - Hash with the following keys:
8
+ # filename - String, file name including extension (e.g., "appendix.pdf")
9
+ # base64 - String, base64-encoded file content
10
+ #
11
+ # == Read-only attributes:
12
+ # id, title, created_at, updated_at
13
+ #
14
+ # == Usage:
15
+ # offer = moco.offers.find(123)
16
+ # offer.attachments.all
17
+ # offer.attachments.create(
18
+ # attachment: {
19
+ # filename: "appendix.pdf",
20
+ # base64: Base64.strict_encode64(File.read("appendix.pdf"))
21
+ # }
22
+ # )
23
+ # offer.attachments.find(42).destroy
24
+ #
25
+ # == Note:
26
+ # The API only supports list (GET), create (POST), and delete (DELETE).
27
+ # Update is not available - delete and re-upload to replace.
28
+ #
29
+ class OfferAttachment < BaseEntity
30
+ def to_s
31
+ title.to_s
32
+ end
33
+ end
34
+ end
@@ -82,15 +82,24 @@ module MOCO
82
82
  MOCO::NestedCollectionProxy.new(client, self, :expenses, "Expense")
83
83
  end
84
84
 
85
- # Fetches tasks associated with this project.
86
- # Always returns a NestedCollectionProxy for consistent interface.
87
- # Data is fetched lazily when accessed (e.g., .all, .first, .each).
88
- # Note: Embedded tasks from projects.assigned are available via attributes[:tasks]
89
- # but may have incomplete fields compared to the dedicated endpoint.
85
+ # Fetches tasks associated with this project via the API.
86
+ # Returns a NestedCollectionProxy for lazy loading and CRUD operations.
90
87
  def tasks
91
88
  MOCO::NestedCollectionProxy.new(client, self, :tasks, "Task")
92
89
  end
93
90
 
91
+ # Returns embedded tasks from the projects/assigned response, or nil.
92
+ # These have fewer fields than the full API response but avoid an
93
+ # extra API call, useful for limited-permission accounts.
94
+ def embedded_tasks
95
+ embedded = attributes[:tasks]
96
+ if embedded.is_a?(Array) && embedded.all? { |t| t.is_a?(MOCO::Task) }
97
+ embedded
98
+ else
99
+ []
100
+ end
101
+ end
102
+
94
103
  # Fetches contracts associated with this project.
95
104
  def contracts
96
105
  MOCO::NestedCollectionProxy.new(client, self, :contracts, "ProjectContract")
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+ require "json"
5
+
6
+ module MOCO
7
+ # Represents a MOCO API session for authentication.
8
+ #
9
+ # The `/session` endpoint exchanges email/password credentials for an
10
+ # API key, and can verify an existing key.
11
+ #
12
+ # == Creating an API key (POST /session):
13
+ # result = MOCO::Session.create(
14
+ # subdomain: "your-account",
15
+ # email: "you@example.com",
16
+ # password: "secret"
17
+ # )
18
+ # result["api_key"] # => "6f95f9a0..."
19
+ # result["user_id"] # => 933590696
20
+ #
21
+ # == Verifying an existing key (GET /session):
22
+ # identity = moco.session.verify
23
+ # identity["id"] # => 933590696
24
+ # identity["uuid"] # => "7a60719d-..."
25
+ #
26
+ # == Note:
27
+ # `create` does not require an existing Client - it uses a temporary
28
+ # unauthenticated connection. `verify` uses the Client's configured
29
+ # API key.
30
+ #
31
+ class Session
32
+ class << self
33
+ # Exchange email/password for an API key. Does not require a Client.
34
+ # Returns a Hash: { "api_key" => "...", "user_id" => ... }
35
+ def create(subdomain:, email:, password:)
36
+ conn = Faraday.new(url: "https://#{subdomain}.mocoapp.com/api/v1") do |f|
37
+ f.request :json
38
+ f.response :json
39
+ end
40
+ response = conn.post("session", { email:, password: })
41
+ raise MOCO::Error, "Authentication failed: #{response.status}" unless response.success?
42
+
43
+ response.body
44
+ end
45
+ end
46
+
47
+ attr_reader :client
48
+
49
+ def initialize(client)
50
+ @client = client
51
+ end
52
+
53
+ # Verify the configured API key. Returns the identity Hash or raises on 401.
54
+ def verify
55
+ client.get("session")
56
+ end
57
+ end
58
+ end
data/lib/moco/entities.rb CHANGED
@@ -44,7 +44,7 @@ module MOCO
44
44
  end
45
45
  end
46
46
 
47
- # https://hundertzehn.github.io/mocoapp-api-docs/sections/projects.html
47
+ # https://docs.mocoapp.com/api/docs/v1#tag/projects.html
48
48
  # @deprecated Use MOCO::Project from entities/project.rb instead
49
49
  class Project < BaseEntity
50
50
  attr_accessor :id, :active, :name, :customer, :tasks
@@ -54,7 +54,7 @@ module MOCO
54
54
  end
55
55
  end
56
56
 
57
- # https://hundertzehn.github.io/mocoapp-api-docs/sections/project_tasks.html
57
+ # https://docs.mocoapp.com/api/docs/v1#tag/project_tasks.html
58
58
  # @deprecated Use MOCO::Task from entities/task.rb instead
59
59
  class Task < BaseEntity
60
60
  attr_accessor :id, :active, :name, :project_id, :billable
@@ -64,7 +64,7 @@ module MOCO
64
64
  end
65
65
  end
66
66
 
67
- # https://hundertzehn.github.io/mocoapp-api-docs/sections/activities.html
67
+ # https://docs.mocoapp.com/api/docs/v1#tag/activities.html
68
68
  # @deprecated Use MOCO::Activity from entities/activity.rb instead
69
69
  class Activity < BaseEntity
70
70
  attr_accessor :id, :active, :date, :description, :project, :task, :seconds, :hours, :billable, :billed, :user,
@@ -79,13 +79,13 @@ module MOCO
79
79
  end
80
80
  end
81
81
 
82
- # https://hundertzehn.github.io/mocoapp-api-docs/sections/companies.html
82
+ # https://docs.mocoapp.com/api/docs/v1#tag/companies.html
83
83
  # @deprecated Use MOCO::Company from entities/company.rb instead
84
84
  class Customer < BaseEntity
85
85
  attr_accessor :id, :name
86
86
  end
87
87
 
88
- # https://hundertzehn.github.io/mocoapp-api-docs/sections/users.html
88
+ # https://docs.mocoapp.com/api/docs/v1#tag/users.html
89
89
  # @deprecated Use MOCO::User from entities/user.rb instead
90
90
  class User < BaseEntity
91
91
  attr_accessor :id, :firstname, :lastname
data/lib/moco/sync.rb CHANGED
@@ -364,7 +364,7 @@ module MOCO
364
364
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
365
365
 
366
366
  def fetch_assigned_projects
367
- # Use .projects.assigned for the source, standard .projects for the target
367
+ # Use .projects.assigned for both source and target to get embedded tasks
368
368
  source_filters = @filters.fetch(:source, {}).merge(active: "true")
369
369
  # Get the proxy, then fetch all results into the instance variable
370
370
  @source_projects = @source.projects.assigned.where(source_filters).all
@@ -372,19 +372,19 @@ module MOCO
372
372
  @source_projects.each do |project|
373
373
  debug_log " Source Project: #{project.id} - #{project.name} (#{project.identifier})"
374
374
  debug_log " Tasks:"
375
- project.tasks.each do |task|
375
+ project.embedded_tasks.each do |task|
376
376
  debug_log " Task: #{task.id} - #{task.name}"
377
377
  end
378
378
  end
379
379
 
380
380
  target_filters = @filters.fetch(:target, {}).merge(active: "true")
381
381
  # Get the proxy, then fetch all results into the instance variable
382
- @target_projects = @target.projects.where(target_filters).all
382
+ @target_projects = @target.projects.assigned.where(target_filters).all
383
383
  debug_log "Found #{@target_projects.size} target projects:"
384
384
  @target_projects.each do |project|
385
385
  debug_log " Target Project: #{project.id} - #{project.name} (#{project.identifier})"
386
386
  debug_log " Tasks:"
387
- project.tasks.each do |task|
387
+ project.embedded_tasks.each do |task|
388
388
  debug_log " Task: #{task.id} - #{task.name}"
389
389
  end
390
390
  end
@@ -401,7 +401,7 @@ module MOCO
401
401
  @project_mapping[source_project.id] = target_project
402
402
  debug_log "Mapped source project #{source_project.id} (#{source_project.name}) to target project #{target_project.id} (#{target_project.name})"
403
403
 
404
- target_project.tasks.each do |target_task|
404
+ target_project.embedded_tasks.each do |target_task|
405
405
  source_task = match_task(target_task, source_project)
406
406
  if source_task
407
407
  @task_mapping[source_task.id] = target_task
@@ -520,7 +520,7 @@ module MOCO
520
520
  return @default_task_cache[target_project.id] if @default_task_cache.key?(target_project.id)
521
521
 
522
522
  # Search for the default task in the target project
523
- default_task = target_project.tasks.find { |task| task.name == @default_task_name }
523
+ default_task = target_project.embedded_tasks.find { |task| task.name == @default_task_name }
524
524
 
525
525
  # Cache the result (even if nil)
526
526
  @default_task_cache[target_project.id] = default_task
@@ -545,7 +545,7 @@ module MOCO
545
545
 
546
546
  def match_task(target_task, source_project)
547
547
  # Get tasks from the source project (embedded in projects.assigned response)
548
- tasks = source_project.tasks
548
+ tasks = source_project.embedded_tasks
549
549
 
550
550
  # Only proceed if we have tasks to match against
551
551
  return nil if tasks.empty?
data/lib/moco/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MOCO
4
- VERSION = "1.2.0"
4
+ VERSION = "1.3.0"
5
5
  end
data/lib/moco.rb CHANGED
@@ -63,7 +63,11 @@ require_relative "moco/entities/recurring_expense"
63
63
  require_relative "moco/entities/invoice_payment"
64
64
  require_relative "moco/entities/invoice_reminder"
65
65
  require_relative "moco/entities/invoice_bookkeeping_export"
66
+ require_relative "moco/entities/invoice_attachment"
66
67
  require_relative "moco/entities/offer_approval"
68
+ require_relative "moco/entities/offer_attachment"
69
+ require_relative "moco/entities/letter_paper"
70
+ require_relative "moco/entities/session"
67
71
  require_relative "moco/entities/purchase_category"
68
72
  require_relative "moco/entities/purchase_draft"
69
73
  require_relative "moco/entities/purchase_payment"
data/sync_activity.rb CHANGED
@@ -94,7 +94,7 @@ syncer = MOCO::Sync.new(
94
94
  syncer.source_projects.each do |project|
95
95
  if syncer.project_mapping[project.id]
96
96
  puts "✅ Project #{project} --> #{syncer.project_mapping[project.id]}"
97
- project.tasks.each do |task|
97
+ project.embedded_tasks.each do |task|
98
98
  if syncer.task_mapping[task.id]
99
99
  puts " ✅ Task #{task} --> #{syncer.task_mapping[task.id]}"
100
100
  else
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moco-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Teal Bauer
@@ -95,11 +95,14 @@ files:
95
95
  - lib/moco/entities/hourly_rate.rb
96
96
  - lib/moco/entities/internal_hourly_rate.rb
97
97
  - lib/moco/entities/invoice.rb
98
+ - lib/moco/entities/invoice_attachment.rb
98
99
  - lib/moco/entities/invoice_bookkeeping_export.rb
99
100
  - lib/moco/entities/invoice_payment.rb
100
101
  - lib/moco/entities/invoice_reminder.rb
102
+ - lib/moco/entities/letter_paper.rb
101
103
  - lib/moco/entities/offer.rb
102
104
  - lib/moco/entities/offer_approval.rb
105
+ - lib/moco/entities/offer_attachment.rb
103
106
  - lib/moco/entities/payment_schedule.rb
104
107
  - lib/moco/entities/planning_entry.rb
105
108
  - lib/moco/entities/presence.rb
@@ -120,6 +123,7 @@ files:
120
123
  - lib/moco/entities/reports/finance.rb
121
124
  - lib/moco/entities/reports/utilization.rb
122
125
  - lib/moco/entities/schedule.rb
126
+ - lib/moco/entities/session.rb
123
127
  - lib/moco/entities/tag.rb
124
128
  - lib/moco/entities/tagging.rb
125
129
  - lib/moco/entities/task.rb
@@ -161,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
161
165
  - !ruby/object:Gem::Version
162
166
  version: '0'
163
167
  requirements: []
164
- rubygems_version: 4.0.3
168
+ rubygems_version: 4.0.10
165
169
  specification_version: 4
166
170
  summary: A Ruby Gem to interact with the MOCO API.
167
171
  test_files: []