A Ruby Gem to interact with the MOCO API. This gem provides a modern, Ruby-esque interface (MOCO::Client) for interacting with the MOCO API.
Install the gem and add to the application's Gemfile by executing:
$ bundle add moco-ruby
If bundler is not being used to manage dependencies, install the gem by executing:
$ gem install moco-ruby
require 'moco'
moco = MOCO::Client.new(
subdomain: "your-subdomain", # Your MOCO subdomain
api_key: "your-api-key" # Your MOCO API key
)Collections are accessed dynamically using pluralized entity names (following Rails conventions):
projects = moco.projects
activities = moco.activities
users = moco.users
# ... and so on for all supported entities# Get all entities in a collection
all_projects = moco.projects.all
# Get entities matching specific criteria
active_projects = moco.projects.where(active: true)
recent_activities = moco.activities.where(date: ">=2024-01-01")
# Get a specific entity by ID
project = moco.projects.find(12345)
user = moco.users.find(678)# Create a new project
new_project = moco.projects.create(
name: "New Website Project",
customer_id: 987,
billable: true
)
puts "Created project: #{new_project.name} (ID: #{new_project.id})"
# Create a new time entry (activity)
new_activity = moco.activities.create(
date: "2024-04-10",
project_id: new_project.id,
task_id: new_project.tasks.first.id, # Assumes project has tasks
hours: 3.5,
description: "Implemented feature X"
)
puts "Created activity: #{new_activity.description} on #{new_activity.date}"Modify attributes and call save:
project = moco.projects.find(12345)
project.name = "Updated Project Name"
project.billable = false
if project.save
puts "Project updated successfully."
else
puts "Failed to update project: #{project.errors.full_messages.join(", ")}" # Assuming error handling exists
end
# You can also update directly via the collection
moco.projects.update(12345, name: "Another Update", active: false)# Delete by object
activity = moco.activities.find(9876)
if activity&.delete
puts "Activity deleted."
end
# Delete by ID via collection
if moco.activities.delete(9876)
puts "Activity deleted."
endEntities provide methods to access related entities easily:
project = moco.projects.find(12345)
# Get tasks associated with the project
tasks = project.tasks # Returns a collection proxy for tasks
puts "Tasks for project '#{project.name}': #{tasks.map(&:name).join(', ')}"
# Get activities for the project
project_activities = project.activities
puts "Activities count: #{project_activities.size}"
# Get the customer (company) for the project
customer = project.customer # Returns a MOCO::Company object
puts "Customer: #{customer.name}"
# ---
activity = moco.activities.find(9876)
# Get the associated project, task, and user
act_project = activity.project
act_task = activity.task
act_user = activity.user
puts "Activity by #{act_user.firstname} on project '#{act_project.name}' (Task: #{act_task.name})"The gem supports ActiveRecord-style operations on nested resources:
project = moco.projects.find(12345)
# Create a new task for the project
new_task = project.tasks.create(
name: "New Feature Development",
billable: true,
active: true,
budget: 40,
hourly_rate: 120
)
puts "Created task: #{new_task.name} (ID: #{new_task.id})"
# Delete all tasks for a project
project.tasks.destroy_all
# Query tasks with conditions
billable_tasks = project.tasks.where(billable: true).all
puts "Billable tasks: #{billable_tasks.map(&:name).join(', ')}"
# Find a specific task
dev_task = project.tasks.find_by(name: "Development")Access the current user's profile:
profile = moco.profile
puts "Logged in as: #{profile.firstname} #{profile.lastname}"Access read-only report endpoints:
# Absences report
absences = moco.reports.absences(year: 2024)
# Utilization report (requires date range)
utilization = moco.reports.utilization(from: "2024-01-01", to: "2024-12-31")
# Financial reports
cashflow = moco.reports.cashflow(from: "2024-01-01", to: "2024-03-31")
finance = moco.reports.finance(from: "2024-01-01", to: "2024-03-31")The gem supports all MOCO API entities with a Ruby-esque interface:
Core:
Project, Activity, User, Company, Task, Invoice, Deal, Expense, WebHook, Schedule, Presence, Holiday, PlanningEntry
Business:
Contact, Offer, Purchase, Receipt, Comment, Tag, Tagging, DealCategory, ProjectGroup, Unit
Account Settings:
CatalogService, CustomProperty, ExpenseTemplate, FixedCost, HourlyRate, InternalHourlyRate, TaskTemplate, UserRole
Financial:
VatCodeSale, VatCodePurchase, PurchaseCategory, PurchaseDraft, PurchaseBudget, PurchasePayment
Bookkeeping:
InvoiceBookkeepingExport, PurchaseBookkeepingExport
Nested Resources:
Employment, WorkTimeAdjustment, ProjectContract, PaymentSchedule, RecurringExpense, InvoicePayment, InvoiceReminder, OfferApproval
Access them via the client using their plural, snake_case names (e.g., moco.planning_entries, moco.vat_code_sales).
These command-line utilities provide helpful shortcuts. They can use credentials and configuration from a config.yml file (see config.yml.sample) in the current directory or accept parameters.
A wrapper around curl to easily make authenticated requests to your MOCO instance API. Useful for testing or exploring endpoints.
Usage: mocurl.rb [options] url
mocurl.rb [options] subdomain path
-X, --method METHOD Set HTTP method to use (GET, POST, PUT, DELETE)
-d, --data DATA Data to send to server (JSON format) for POST/PUT
-a, --api-key API_KEY Manually specify MOCO API key (overrides config.yml)
-n, --no-format Disable JSON pretty-printing of the response
-v, --verbose Show additional request and response information
-h, --help Show this message
Example: mocurl.rb your-subdomain projects/12345
Syncs activity data (time entries) between two MOCO instances (source and target). It uses fuzzy matching to map projects and tasks between the instances.
Important:
- Always use
--dry-runfirst to verify the matching and intended actions. - Use date filters (
--from,--to) to limit the scope.
Usage: sync_activity.rb [options] source_subdomain target_subdomain
-f, --from DATE Start date for sync (YYYY-MM-DD)
-t, --to DATE End date for sync (YYYY-MM-DD)
-p, --project PROJECT_ID Source Project ID to filter by (optional)
-c, --company COMPANY_ID Source Company ID to filter by (optional)
-g, --term TERM Term to filter source activities by (optional)
-n, --dry-run Perform matching and show planned actions, but do not modify target instance
--match-project-threshold VALUE
Fuzzy match threshold for projects (0.0 - 1.0), default 0.8
--match-task-threshold VALUE Fuzzy match threshold for tasks (0.0 - 1.0), default 0.45
--default-task TASK_NAME Map unmatched tasks to this default task instead of creating new tasks
-d, --debug Enable debug output
-h, --help Show this message
Example: sync_activity.rb --from 2024-04-01 --to 2024-04-10 --dry-run source-instance target-instance
Using Default Task Mapping: If your target account has limited permissions and cannot create tasks, or if you want to consolidate multiple source tasks into a single target task, use the --default-task flag:
sync_activity.rb --from 2024-04-01 --to 2024-04-10 --default-task "Other" source-instance target-instanceThis will map any unmatched source tasks to a task named "Other" in the corresponding target project, avoiding the need to create new tasks.
After checking out the repo, run bin/setup to install dependencies.
The gem includes unit tests (mocked) and integration tests (live API):
# Unit tests (mocked, fast)
bundle exec ruby -Ilib -Itest test/test_v2_api.rb
bundle exec ruby -Ilib -Itest test/test_new_entities.rb
# Integration tests (requires .env credentials)
bundle exec ruby -Ilib -Itest test/test_integration.rb
bundle exec ruby -Ilib -Itest test/test_comprehensive.rbFor integration tests, create a .env file with your test instance credentials:
MOCO_API_TEST_SUBDOMAIN=your-test-subdomain
MOCO_API_TEST_API_KEY=your-test-api-key
Note: The MOCO API has rate limits. The gem automatically retries rate-limited requests with exponential backoff.
To install this gem onto your local machine, run bundle exec rake install.
To release a new version, update the version number in version.rb, update the CHANGELOG.md, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/starsong-consulting/moco-ruby.
The gem is available as open source under the terms of the Apache License, Version 2.0.