moco-ruby 1.1.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 +4 -4
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +56 -1
- data/Gemfile.lock +45 -40
- data/README.md +98 -25
- data/lib/moco/client.rb +65 -0
- data/lib/moco/connection.rb +45 -22
- data/lib/moco/entities/activity.rb +31 -1
- data/lib/moco/entities/catalog_service.rb +54 -0
- data/lib/moco/entities/comment.rb +61 -0
- data/lib/moco/entities/company.rb +57 -2
- data/lib/moco/entities/contact.rb +56 -0
- data/lib/moco/entities/custom_property.rb +49 -0
- data/lib/moco/entities/deal.rb +38 -2
- data/lib/moco/entities/deal_category.rb +27 -0
- data/lib/moco/entities/employment.rb +55 -0
- data/lib/moco/entities/expense.rb +37 -2
- data/lib/moco/entities/expense_template.rb +39 -0
- data/lib/moco/entities/fixed_cost.rb +30 -0
- data/lib/moco/entities/holiday.rb +33 -2
- data/lib/moco/entities/hourly_rate.rb +33 -0
- data/lib/moco/entities/internal_hourly_rate.rb +32 -0
- data/lib/moco/entities/invoice.rb +70 -1
- data/lib/moco/entities/invoice_attachment.rb +34 -0
- data/lib/moco/entities/invoice_bookkeeping_export.rb +33 -0
- data/lib/moco/entities/invoice_payment.rb +51 -0
- data/lib/moco/entities/invoice_reminder.rb +51 -0
- data/lib/moco/entities/letter_paper.rb +23 -0
- data/lib/moco/entities/offer.rb +111 -0
- data/lib/moco/entities/offer_approval.rb +42 -0
- data/lib/moco/entities/offer_attachment.rb +34 -0
- data/lib/moco/entities/payment_schedule.rb +48 -0
- data/lib/moco/entities/planning_entry.rb +43 -2
- data/lib/moco/entities/presence.rb +34 -2
- data/lib/moco/entities/profile.rb +24 -0
- data/lib/moco/entities/project.rb +85 -10
- data/lib/moco/entities/project_contract.rb +50 -0
- data/lib/moco/entities/project_group.rb +38 -0
- data/lib/moco/entities/purchase.rb +90 -0
- data/lib/moco/entities/purchase_bookkeeping_export.rb +34 -0
- data/lib/moco/entities/purchase_budget.rb +47 -0
- data/lib/moco/entities/purchase_category.rb +38 -0
- data/lib/moco/entities/purchase_draft.rb +25 -0
- data/lib/moco/entities/purchase_payment.rb +51 -0
- data/lib/moco/entities/receipt.rb +55 -0
- data/lib/moco/entities/recurring_expense.rb +55 -0
- data/lib/moco/entities/reports/absences.rb +16 -0
- data/lib/moco/entities/reports/cashflow.rb +16 -0
- data/lib/moco/entities/reports/finance.rb +16 -0
- data/lib/moco/entities/reports/utilization.rb +16 -0
- data/lib/moco/entities/schedule.rb +39 -2
- data/lib/moco/entities/session.rb +58 -0
- data/lib/moco/entities/tag.rb +30 -0
- data/lib/moco/entities/tagging.rb +27 -0
- data/lib/moco/entities/task.rb +25 -2
- data/lib/moco/entities/task_template.rb +38 -0
- data/lib/moco/entities/unit.rb +36 -0
- data/lib/moco/entities/user.rb +50 -2
- data/lib/moco/entities/user_role.rb +29 -0
- data/lib/moco/entities/vat_code_purchase.rb +29 -0
- data/lib/moco/entities/vat_code_sale.rb +29 -0
- data/lib/moco/entities/web_hook.rb +32 -2
- data/lib/moco/entities/work_time_adjustment.rb +51 -0
- data/lib/moco/entities.rb +5 -5
- data/lib/moco/sync.rb +7 -7
- data/lib/moco/version.rb +1 -1
- data/lib/moco.rb +55 -1
- data/moco.gemspec +38 -0
- data/sync_activity.rb +1 -1
- metadata +51 -8
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents a MOCO tag/label
|
|
5
|
+
#
|
|
6
|
+
# == Required attributes for create:
|
|
7
|
+
# name - String, tag name (e.g., "Important")
|
|
8
|
+
# context - String, entity type this tag applies to:
|
|
9
|
+
# "Project", "Contact", "Company", "Deal", "Offer",
|
|
10
|
+
# "Invoice", "Purchase", "User"
|
|
11
|
+
#
|
|
12
|
+
# == Read-only attributes:
|
|
13
|
+
# id, created_at, updated_at
|
|
14
|
+
#
|
|
15
|
+
# == Example:
|
|
16
|
+
# moco.tags.create(
|
|
17
|
+
# name: "Priority",
|
|
18
|
+
# context: "Project"
|
|
19
|
+
# )
|
|
20
|
+
#
|
|
21
|
+
# == Note:
|
|
22
|
+
# To apply tags to entities, use the `tags` attribute when
|
|
23
|
+
# creating/updating the entity: { tags: ["Tag1", "Tag2"] }
|
|
24
|
+
#
|
|
25
|
+
class Tag < BaseEntity
|
|
26
|
+
def to_s
|
|
27
|
+
name.to_s
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents a MOCO tagging (association between a tag and an entity)
|
|
5
|
+
# This is a read-only entity representing tag assignments.
|
|
6
|
+
#
|
|
7
|
+
# == Read-only attributes:
|
|
8
|
+
# id, entity_id, entity_type, tag (Hash), created_at, updated_at
|
|
9
|
+
#
|
|
10
|
+
# == Note:
|
|
11
|
+
# To apply tags to entities, use the `tags` attribute when
|
|
12
|
+
# creating/updating the entity directly:
|
|
13
|
+
# moco.projects.update(123, tags: ["Priority", "Important"])
|
|
14
|
+
#
|
|
15
|
+
# See also: Tag entity for managing available tags.
|
|
16
|
+
#
|
|
17
|
+
class Tagging < BaseEntity
|
|
18
|
+
# Associations
|
|
19
|
+
def tag
|
|
20
|
+
association(:tag)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def to_s
|
|
24
|
+
"Tagging ##{id}"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/moco/entities/task.rb
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module MOCO
|
|
4
|
-
# Represents a MOCO task
|
|
5
|
-
#
|
|
4
|
+
# Represents a MOCO task (project service/activity type)
|
|
5
|
+
# Tasks are nested under projects: project.tasks.create(...)
|
|
6
|
+
#
|
|
7
|
+
# == Required attributes for create:
|
|
8
|
+
# name - String, task name (e.g., "Development", "Design / UX")
|
|
9
|
+
#
|
|
10
|
+
# == Optional attributes:
|
|
11
|
+
# billable - Boolean, whether time on this task is billable
|
|
12
|
+
# active - Boolean, whether task is active
|
|
13
|
+
# budget - Float/Integer, budget in hours or currency
|
|
14
|
+
# hourly_rate - Float/Integer, rate for this task (used if project billing_variant is "task")
|
|
15
|
+
# description - String, task description
|
|
16
|
+
#
|
|
17
|
+
# == Read-only attributes (returned by API):
|
|
18
|
+
# id, created_at, updated_at
|
|
19
|
+
#
|
|
20
|
+
# == Example:
|
|
21
|
+
# project = moco.projects.find(123)
|
|
22
|
+
# project.tasks.create(
|
|
23
|
+
# name: "Development",
|
|
24
|
+
# billable: true,
|
|
25
|
+
# hourly_rate: 150,
|
|
26
|
+
# budget: 100
|
|
27
|
+
# )
|
|
28
|
+
#
|
|
6
29
|
class Task < BaseEntity
|
|
7
30
|
# Associations
|
|
8
31
|
def project
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents a MOCO task template (Standardleistungen)
|
|
5
|
+
# Pre-defined task types for projects
|
|
6
|
+
#
|
|
7
|
+
# == Required attributes for create:
|
|
8
|
+
# name - String, task name (e.g., "Development", "Design")
|
|
9
|
+
#
|
|
10
|
+
# == Optional attributes:
|
|
11
|
+
# description - String, task description
|
|
12
|
+
# revenue_category_id - Integer, revenue category for invoicing
|
|
13
|
+
# billable - Boolean, whether tasks are billable by default
|
|
14
|
+
# project_default - Boolean, auto-add to new projects
|
|
15
|
+
# index - Integer, display order (e.g., 10, 20, 30)
|
|
16
|
+
#
|
|
17
|
+
# == Read-only attributes:
|
|
18
|
+
# id, revenue_category (Hash), created_at, updated_at
|
|
19
|
+
#
|
|
20
|
+
# == Example:
|
|
21
|
+
# moco.task_templates.create(
|
|
22
|
+
# name: "Backend Development",
|
|
23
|
+
# description: "Server-side programming",
|
|
24
|
+
# billable: true,
|
|
25
|
+
# project_default: true,
|
|
26
|
+
# index: 10
|
|
27
|
+
# )
|
|
28
|
+
#
|
|
29
|
+
class TaskTemplate < BaseEntity
|
|
30
|
+
def self.entity_path
|
|
31
|
+
"account/task_templates"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def to_s
|
|
35
|
+
name.to_s
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents a MOCO unit/team (Teams)
|
|
5
|
+
#
|
|
6
|
+
# == Required attributes for create:
|
|
7
|
+
# name - String, team name (e.g., "Development Team")
|
|
8
|
+
#
|
|
9
|
+
# == Read-only attributes:
|
|
10
|
+
# id, users (Array of user hashes), created_at, updated_at
|
|
11
|
+
#
|
|
12
|
+
# == Example:
|
|
13
|
+
# # Create a new team
|
|
14
|
+
# moco.units.create(name: "Marketing Team")
|
|
15
|
+
#
|
|
16
|
+
# # Get users in a team
|
|
17
|
+
# team = moco.units.find(123)
|
|
18
|
+
# team.users # => Array of User objects
|
|
19
|
+
#
|
|
20
|
+
# == Note:
|
|
21
|
+
# To assign users to a team, update the user with unit_id:
|
|
22
|
+
# moco.users.update(user_id, unit_id: team.id)
|
|
23
|
+
#
|
|
24
|
+
# Deleting a unit is only possible if no users are assigned to it.
|
|
25
|
+
#
|
|
26
|
+
class Unit < BaseEntity
|
|
27
|
+
# Get users belonging to this unit
|
|
28
|
+
def users
|
|
29
|
+
has_many(:users, :unit_id)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def to_s
|
|
33
|
+
name.to_s
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/moco/entities/user.rb
CHANGED
|
@@ -1,8 +1,44 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module MOCO
|
|
4
|
-
# Represents a MOCO user
|
|
5
|
-
#
|
|
4
|
+
# Represents a MOCO user (staff member)
|
|
5
|
+
#
|
|
6
|
+
# == Required attributes for create:
|
|
7
|
+
# firstname - String, first name
|
|
8
|
+
# lastname - String, last name
|
|
9
|
+
# email - String, email address (used for login)
|
|
10
|
+
# unit_id - Integer, team/unit ID
|
|
11
|
+
#
|
|
12
|
+
# == Optional attributes:
|
|
13
|
+
# password - String, initial password (if not set, user gets welcome email)
|
|
14
|
+
# role_id - Integer, permission role ID
|
|
15
|
+
# active - Boolean, whether user is active
|
|
16
|
+
# external - Boolean, true for contractors/external staff
|
|
17
|
+
# language - String, one of: "de", "de-AT", "de-CH", "en", "it", "fr"
|
|
18
|
+
# mobile_phone - String, mobile phone number
|
|
19
|
+
# work_phone - String, work phone number
|
|
20
|
+
# home_address - String, home address (use \n for line breaks)
|
|
21
|
+
# bday - String, birthday "YYYY-MM-DD"
|
|
22
|
+
# iban - String, bank account IBAN
|
|
23
|
+
# tags - Array of Strings, e.g., ["Developer", "Remote"]
|
|
24
|
+
# custom_properties - Hash, e.g., {"Start Date": "2024-01-01"}
|
|
25
|
+
# info - String, additional notes
|
|
26
|
+
# welcome_email - Boolean, send welcome email (default: true if no password)
|
|
27
|
+
# avatar - Hash, { filename: "photo.jpg", base64: "..." }
|
|
28
|
+
#
|
|
29
|
+
# == Read-only attributes:
|
|
30
|
+
# id, avatar_url, unit (Hash), role (Hash), created_at, updated_at
|
|
31
|
+
#
|
|
32
|
+
# == Example:
|
|
33
|
+
# moco.users.create(
|
|
34
|
+
# firstname: "John",
|
|
35
|
+
# lastname: "Doe",
|
|
36
|
+
# email: "john.doe@company.com",
|
|
37
|
+
# unit_id: 123,
|
|
38
|
+
# language: "en",
|
|
39
|
+
# tags: ["Developer"]
|
|
40
|
+
# )
|
|
41
|
+
#
|
|
6
42
|
class User < BaseEntity
|
|
7
43
|
# Instance methods for user-specific operations
|
|
8
44
|
def performance_report
|
|
@@ -22,6 +58,18 @@ module MOCO
|
|
|
22
58
|
has_many(:holidays)
|
|
23
59
|
end
|
|
24
60
|
|
|
61
|
+
def employments
|
|
62
|
+
has_many(:employments)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def work_time_adjustments
|
|
66
|
+
has_many(:work_time_adjustments)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def unit
|
|
70
|
+
association(:unit)
|
|
71
|
+
end
|
|
72
|
+
|
|
25
73
|
def full_name
|
|
26
74
|
"#{firstname} #{lastname}"
|
|
27
75
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents a MOCO user permission role
|
|
5
|
+
# Read-only list of available permission roles
|
|
6
|
+
#
|
|
7
|
+
# == Read-only attributes:
|
|
8
|
+
# id, name, created_at, updated_at
|
|
9
|
+
#
|
|
10
|
+
# == Common roles:
|
|
11
|
+
# - Admin
|
|
12
|
+
# - Manager
|
|
13
|
+
# - Coworker
|
|
14
|
+
# - etc.
|
|
15
|
+
#
|
|
16
|
+
# == Note:
|
|
17
|
+
# Permission roles are configured in MOCO's admin interface.
|
|
18
|
+
# Use role_id when creating/updating users to assign a role.
|
|
19
|
+
#
|
|
20
|
+
class UserRole < BaseEntity
|
|
21
|
+
def self.entity_path
|
|
22
|
+
"users/roles"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_s
|
|
26
|
+
name.to_s
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents a MOCO purchase VAT code (Steuerschlüssel Einkauf)
|
|
5
|
+
# Read-only VAT rates for purchases/receipts
|
|
6
|
+
#
|
|
7
|
+
# == Read-only attributes:
|
|
8
|
+
# id, code, tax, reverse_charge, intra_eu, active
|
|
9
|
+
#
|
|
10
|
+
# == Filtering:
|
|
11
|
+
# moco.vat_code_purchases.where(active: true)
|
|
12
|
+
# moco.vat_code_purchases.where(reverse_charge: true)
|
|
13
|
+
# moco.vat_code_purchases.where(intra_eu: true)
|
|
14
|
+
# moco.vat_code_purchases.where(ids: "123,456")
|
|
15
|
+
#
|
|
16
|
+
# == Note:
|
|
17
|
+
# VAT codes are configured in MOCO's admin interface.
|
|
18
|
+
# Use vat_code_id when creating purchases/receipts.
|
|
19
|
+
#
|
|
20
|
+
class VatCodePurchase < BaseEntity
|
|
21
|
+
def self.entity_path
|
|
22
|
+
"vat_code_purchases"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_s
|
|
26
|
+
"#{code} - #{name}"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents a MOCO sales VAT code (Steuerschlüssel Verkauf)
|
|
5
|
+
# Read-only VAT rates for invoices/offers
|
|
6
|
+
#
|
|
7
|
+
# == Read-only attributes:
|
|
8
|
+
# id, code, tax, reverse_charge, intra_eu, active,
|
|
9
|
+
# print_gross_total, notice_tax_exemption, credit_account
|
|
10
|
+
#
|
|
11
|
+
# == Filtering:
|
|
12
|
+
# moco.vat_code_sales.where(active: true)
|
|
13
|
+
# moco.vat_code_sales.where(reverse_charge: true)
|
|
14
|
+
# moco.vat_code_sales.where(intra_eu: true) # EU intra-community
|
|
15
|
+
#
|
|
16
|
+
# == Note:
|
|
17
|
+
# VAT codes are configured in MOCO's admin interface.
|
|
18
|
+
# Use vat_code_id when creating invoices/offers.
|
|
19
|
+
#
|
|
20
|
+
class VatCodeSale < BaseEntity
|
|
21
|
+
def self.entity_path
|
|
22
|
+
"vat_code_sales"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_s
|
|
26
|
+
"#{code} - #{name}"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -1,8 +1,38 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module MOCO
|
|
4
|
-
# Represents a MOCO webhook
|
|
5
|
-
#
|
|
4
|
+
# Represents a MOCO webhook for event notifications
|
|
5
|
+
#
|
|
6
|
+
# == Required attributes for create:
|
|
7
|
+
# target - String, entity type to watch:
|
|
8
|
+
# "Activity", "Company", "Contact", "Project",
|
|
9
|
+
# "Invoice", "Offer", "Deal", "Expense"
|
|
10
|
+
# event - String, event type: "create", "update", "delete"
|
|
11
|
+
# hook - String, URL to receive webhook payloads (e.g., "https://example.org/callback")
|
|
12
|
+
#
|
|
13
|
+
# == Read-only attributes:
|
|
14
|
+
# id, disabled, disabled_at, created_at, updated_at
|
|
15
|
+
#
|
|
16
|
+
# == Instance methods:
|
|
17
|
+
# enable - Enable the webhook
|
|
18
|
+
# disable - Disable the webhook
|
|
19
|
+
#
|
|
20
|
+
# == Example:
|
|
21
|
+
# # Create webhook for new activities
|
|
22
|
+
# moco.web_hooks.create(
|
|
23
|
+
# target: "Activity",
|
|
24
|
+
# event: "create",
|
|
25
|
+
# hook: "https://example.org/moco-activity-webhook"
|
|
26
|
+
# )
|
|
27
|
+
#
|
|
28
|
+
# # Disable a webhook
|
|
29
|
+
# webhook = moco.web_hooks.find(123)
|
|
30
|
+
# webhook.disable
|
|
31
|
+
#
|
|
32
|
+
# == Note:
|
|
33
|
+
# Only the `hook` URL can be updated after creation.
|
|
34
|
+
# To change target/event, delete and recreate the webhook.
|
|
35
|
+
#
|
|
6
36
|
class WebHook < BaseEntity
|
|
7
37
|
# Override entity_path to match API path
|
|
8
38
|
def self.entity_path
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents a MOCO user work time adjustment record
|
|
5
|
+
# (Korrekturen Zeiterfassung) for overtime/undertime corrections
|
|
6
|
+
#
|
|
7
|
+
# == Required attributes for create:
|
|
8
|
+
# user_id - Integer, user to adjust
|
|
9
|
+
# date - String, "YYYY-MM-DD" effective date
|
|
10
|
+
# description - String, reason for adjustment
|
|
11
|
+
# hours - Float, hours to add (positive) or subtract (negative)
|
|
12
|
+
#
|
|
13
|
+
# == Read-only attributes:
|
|
14
|
+
# id, user (Hash), creator (Hash), created_at, updated_at
|
|
15
|
+
#
|
|
16
|
+
# == Example:
|
|
17
|
+
# # Add overtime from previous year
|
|
18
|
+
# moco.work_time_adjustments.create(
|
|
19
|
+
# user_id: 123,
|
|
20
|
+
# date: "2024-01-01",
|
|
21
|
+
# description: "Overtime carryover from 2023",
|
|
22
|
+
# hours: 42.0
|
|
23
|
+
# )
|
|
24
|
+
#
|
|
25
|
+
# # Correct time balance
|
|
26
|
+
# moco.work_time_adjustments.create(
|
|
27
|
+
# user_id: 123,
|
|
28
|
+
# date: "2024-06-15",
|
|
29
|
+
# description: "Correction for unpaid leave",
|
|
30
|
+
# hours: -16.0
|
|
31
|
+
# )
|
|
32
|
+
#
|
|
33
|
+
# == Filtering:
|
|
34
|
+
# moco.work_time_adjustments.where(user_id: 123)
|
|
35
|
+
# moco.work_time_adjustments.where(from: "2024-01-01", to: "2024-12-31")
|
|
36
|
+
#
|
|
37
|
+
class WorkTimeAdjustment < BaseEntity
|
|
38
|
+
def self.entity_path
|
|
39
|
+
"users/work_time_adjustments"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Associations
|
|
43
|
+
def user
|
|
44
|
+
association(:user)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def to_s
|
|
48
|
+
"WorkTimeAdjustment ##{id} (#{date})"
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
data/lib/moco/entities.rb
CHANGED
|
@@ -44,7 +44,7 @@ module MOCO
|
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
# https://
|
|
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://
|
|
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://
|
|
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://
|
|
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://
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
data/lib/moco.rb
CHANGED
|
@@ -11,8 +11,10 @@ require_relative "moco/connection"
|
|
|
11
11
|
require_relative "moco/collection_proxy"
|
|
12
12
|
require_relative "moco/nested_collection_proxy"
|
|
13
13
|
|
|
14
|
-
#
|
|
14
|
+
# Entities
|
|
15
15
|
require_relative "moco/entities/base_entity"
|
|
16
|
+
|
|
17
|
+
# Core entities (original)
|
|
16
18
|
require_relative "moco/entities/project"
|
|
17
19
|
require_relative "moco/entities/activity"
|
|
18
20
|
require_relative "moco/entities/user"
|
|
@@ -26,6 +28,58 @@ require_relative "moco/entities/schedule"
|
|
|
26
28
|
require_relative "moco/entities/presence"
|
|
27
29
|
require_relative "moco/entities/holiday"
|
|
28
30
|
require_relative "moco/entities/planning_entry"
|
|
31
|
+
|
|
32
|
+
# New standalone entities
|
|
33
|
+
require_relative "moco/entities/contact"
|
|
34
|
+
require_relative "moco/entities/offer"
|
|
35
|
+
require_relative "moco/entities/purchase"
|
|
36
|
+
require_relative "moco/entities/receipt"
|
|
37
|
+
require_relative "moco/entities/unit"
|
|
38
|
+
require_relative "moco/entities/comment"
|
|
39
|
+
require_relative "moco/entities/tag"
|
|
40
|
+
require_relative "moco/entities/tagging"
|
|
41
|
+
require_relative "moco/entities/deal_category"
|
|
42
|
+
require_relative "moco/entities/project_group"
|
|
43
|
+
require_relative "moco/entities/profile"
|
|
44
|
+
|
|
45
|
+
# Account-level entities
|
|
46
|
+
require_relative "moco/entities/catalog_service"
|
|
47
|
+
require_relative "moco/entities/custom_property"
|
|
48
|
+
require_relative "moco/entities/expense_template"
|
|
49
|
+
require_relative "moco/entities/fixed_cost"
|
|
50
|
+
require_relative "moco/entities/hourly_rate"
|
|
51
|
+
require_relative "moco/entities/internal_hourly_rate"
|
|
52
|
+
require_relative "moco/entities/task_template"
|
|
53
|
+
require_relative "moco/entities/user_role"
|
|
54
|
+
require_relative "moco/entities/vat_code_sale"
|
|
55
|
+
require_relative "moco/entities/vat_code_purchase"
|
|
56
|
+
|
|
57
|
+
# Nested/sub-resource entities
|
|
58
|
+
require_relative "moco/entities/employment"
|
|
59
|
+
require_relative "moco/entities/work_time_adjustment"
|
|
60
|
+
require_relative "moco/entities/project_contract"
|
|
61
|
+
require_relative "moco/entities/payment_schedule"
|
|
62
|
+
require_relative "moco/entities/recurring_expense"
|
|
63
|
+
require_relative "moco/entities/invoice_payment"
|
|
64
|
+
require_relative "moco/entities/invoice_reminder"
|
|
65
|
+
require_relative "moco/entities/invoice_bookkeeping_export"
|
|
66
|
+
require_relative "moco/entities/invoice_attachment"
|
|
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"
|
|
71
|
+
require_relative "moco/entities/purchase_category"
|
|
72
|
+
require_relative "moco/entities/purchase_draft"
|
|
73
|
+
require_relative "moco/entities/purchase_payment"
|
|
74
|
+
require_relative "moco/entities/purchase_budget"
|
|
75
|
+
require_relative "moco/entities/purchase_bookkeeping_export"
|
|
76
|
+
|
|
77
|
+
# Reports
|
|
78
|
+
require_relative "moco/entities/reports/absences"
|
|
79
|
+
require_relative "moco/entities/reports/cashflow"
|
|
80
|
+
require_relative "moco/entities/reports/finance"
|
|
81
|
+
require_relative "moco/entities/reports/utilization"
|
|
82
|
+
|
|
29
83
|
require_relative "moco/client"
|
|
30
84
|
require_relative "moco/entity_collection"
|
|
31
85
|
|
data/moco.gemspec
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/moco/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "moco-ruby"
|
|
7
|
+
spec.version = MOCO::VERSION
|
|
8
|
+
spec.authors = ["Teal Bauer"]
|
|
9
|
+
spec.email = ["rubygems@teal.is"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "A Ruby Gem to interact with the MOCO API."
|
|
12
|
+
spec.description = "A modern, Ruby-esque interface for the MOCO API (mocoapp.com). " \
|
|
13
|
+
"Provides an ActiveRecord-style interface for projects, activities, users, companies, and more."
|
|
14
|
+
spec.homepage = "https://github.com/starsong-consulting/moco-ruby"
|
|
15
|
+
spec.required_ruby_version = ">= 3.2.0"
|
|
16
|
+
spec.license = "Apache-2.0"
|
|
17
|
+
|
|
18
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
19
|
+
spec.metadata["source_code_uri"] = "https://github.com/starsong-consulting/moco-ruby"
|
|
20
|
+
spec.metadata["changelog_uri"] = "https://github.com/starsong-consulting/moco-ruby/blob/main/CHANGELOG.md"
|
|
21
|
+
|
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
24
|
+
spec.files = Dir.chdir(__dir__) do
|
|
25
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
26
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|circleci)|appveyor)})
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
spec.bindir = "exe"
|
|
30
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
31
|
+
spec.require_paths = ["lib"]
|
|
32
|
+
|
|
33
|
+
spec.add_dependency "activesupport", ">= 7.0"
|
|
34
|
+
spec.add_dependency "faraday", ">= 2.0"
|
|
35
|
+
spec.add_dependency "fuzzy_match", "~> 2.1.0"
|
|
36
|
+
|
|
37
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
|
38
|
+
end
|
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.
|
|
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
|