moco-ruby 1.1.0 → 1.2.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/CHANGELOG.md +36 -1
- data/Gemfile.lock +44 -40
- data/README.md +53 -24
- data/lib/moco/client.rb +58 -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 +81 -1
- 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/offer.rb +122 -0
- data/lib/moco/entities/offer_approval.rb +42 -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 +76 -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/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/version.rb +1 -1
- data/lib/moco.rb +51 -1
- data/moco.gemspec +38 -0
- metadata +47 -8
|
@@ -1,8 +1,63 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module MOCO
|
|
4
|
-
# Represents a MOCO company (customer)
|
|
5
|
-
#
|
|
4
|
+
# Represents a MOCO company (customer, supplier, or organization)
|
|
5
|
+
#
|
|
6
|
+
# == Required attributes for create:
|
|
7
|
+
# name - String, company name (e.g., "Acme Corp")
|
|
8
|
+
# type - String, one of: "customer", "supplier", "organization"
|
|
9
|
+
# currency - String, 3-letter code (e.g., "EUR") - required for customers only
|
|
10
|
+
#
|
|
11
|
+
# == Optional attributes (all types):
|
|
12
|
+
# identifier - String, company identifier (e.g., "K-123") - required if manual numbering
|
|
13
|
+
# country_code - String, ISO Alpha-2 code in uppercase (e.g., "DE", "CH", "US")
|
|
14
|
+
# vat_identifier - String, EU VAT ID (e.g., "DE123456789")
|
|
15
|
+
# website - String, company website URL
|
|
16
|
+
# phone - String, phone number
|
|
17
|
+
# fax - String, fax number
|
|
18
|
+
# email - String, main email address
|
|
19
|
+
# billing_email_cc - String, CC for billing emails
|
|
20
|
+
# billing_notes - String, notes for billing
|
|
21
|
+
# address - String, full address (use \n for line breaks)
|
|
22
|
+
# info - String, additional information
|
|
23
|
+
# tags - Array of Strings, e.g., ["Network", "Print"]
|
|
24
|
+
# custom_properties - Hash, e.g., {"UID": "123-ABC"}
|
|
25
|
+
# user_id - Integer, responsible person (user ID)
|
|
26
|
+
# footer - String, HTML footer for invoices
|
|
27
|
+
# alternative_correspondence_language - Boolean, use alternative language
|
|
28
|
+
#
|
|
29
|
+
# == Customer-specific attributes:
|
|
30
|
+
# customer_tax - Float, tax rate for customer (e.g., 19.0)
|
|
31
|
+
# default_invoice_due_days - Integer, payment terms (e.g., 30)
|
|
32
|
+
# debit_number - Integer, for bookkeeping (e.g., 10000)
|
|
33
|
+
#
|
|
34
|
+
# == Supplier-specific attributes:
|
|
35
|
+
# bank_owner - String, bank account holder name
|
|
36
|
+
# iban - String, bank account IBAN
|
|
37
|
+
# bank_bic - String, bank BIC/SWIFT code
|
|
38
|
+
# supplier_tax - Float, tax rate for supplier
|
|
39
|
+
# credit_number - Integer, for bookkeeping (e.g., 70000)
|
|
40
|
+
#
|
|
41
|
+
# == Read-only attributes (returned by API):
|
|
42
|
+
# id, intern, projects (Array), user (Hash), created_at, updated_at
|
|
43
|
+
#
|
|
44
|
+
# == Example:
|
|
45
|
+
# # Create a customer
|
|
46
|
+
# moco.companies.create(
|
|
47
|
+
# name: "Acme Corp",
|
|
48
|
+
# type: "customer",
|
|
49
|
+
# currency: "EUR",
|
|
50
|
+
# country_code: "DE",
|
|
51
|
+
# email: "info@acme.com"
|
|
52
|
+
# )
|
|
53
|
+
#
|
|
54
|
+
# # Create a supplier
|
|
55
|
+
# moco.companies.create(
|
|
56
|
+
# name: "Office Supplies Inc",
|
|
57
|
+
# type: "supplier",
|
|
58
|
+
# iban: "DE89370400440532013000"
|
|
59
|
+
# )
|
|
60
|
+
#
|
|
6
61
|
class Company < BaseEntity
|
|
7
62
|
# Associations
|
|
8
63
|
def projects
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents a MOCO contact (person/Ansprechpartner)
|
|
5
|
+
# Contacts are people associated with companies
|
|
6
|
+
#
|
|
7
|
+
# == Required attributes for create:
|
|
8
|
+
# lastname - String, last name (e.g., "Muster")
|
|
9
|
+
# gender - String, one of: "F" (female), "M" (male), "U" (unknown/diverse)
|
|
10
|
+
#
|
|
11
|
+
# == Optional attributes:
|
|
12
|
+
# firstname - String, first name
|
|
13
|
+
# company_id - Integer, associated company ID
|
|
14
|
+
# user_id - Integer, responsible user ID (default: current user)
|
|
15
|
+
# title - String, title (e.g., "Dr.", "Prof.")
|
|
16
|
+
# job_position - String, job title (e.g., "Account Manager")
|
|
17
|
+
# mobile_phone - String, mobile phone number
|
|
18
|
+
# work_phone - String, work phone number
|
|
19
|
+
# work_fax - String, work fax number
|
|
20
|
+
# work_email - String, work email address
|
|
21
|
+
# work_address - String, work address (use \n for line breaks)
|
|
22
|
+
# home_email - String, personal email
|
|
23
|
+
# home_address - String, home address
|
|
24
|
+
# birthday - String, "YYYY-MM-DD" format (e.g., "1990-05-22")
|
|
25
|
+
# info - String, additional notes
|
|
26
|
+
# tags - Array of Strings, e.g., ["VIP", "Newsletter"]
|
|
27
|
+
#
|
|
28
|
+
# == Read-only attributes (returned by API):
|
|
29
|
+
# id, avatar_url, company (Hash), created_at, updated_at
|
|
30
|
+
#
|
|
31
|
+
# == Example:
|
|
32
|
+
# moco.contacts.create(
|
|
33
|
+
# firstname: "John",
|
|
34
|
+
# lastname: "Doe",
|
|
35
|
+
# gender: "M",
|
|
36
|
+
# company_id: 123456,
|
|
37
|
+
# work_email: "john.doe@example.com",
|
|
38
|
+
# job_position: "CTO"
|
|
39
|
+
# )
|
|
40
|
+
#
|
|
41
|
+
class Contact < BaseEntity
|
|
42
|
+
# Override entity_path to match API path
|
|
43
|
+
def self.entity_path
|
|
44
|
+
"contacts/people"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Associations
|
|
48
|
+
def company
|
|
49
|
+
association(:company)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def to_s
|
|
53
|
+
"#{firstname} #{lastname}"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents a MOCO custom property/field definition (Eigene Felder)
|
|
5
|
+
#
|
|
6
|
+
# == Required attributes for create:
|
|
7
|
+
# name - String, field name (e.g., "Purchase Order Number")
|
|
8
|
+
# kind - String, field type:
|
|
9
|
+
# "String", "Textarea", "Link", "Boolean",
|
|
10
|
+
# "Select", "MultiSelect", "Date"
|
|
11
|
+
# entity - String, entity type this field applies to:
|
|
12
|
+
# "Project", "Customer", "Deal", etc.
|
|
13
|
+
#
|
|
14
|
+
# == Optional attributes:
|
|
15
|
+
# placeholder - String, placeholder text for input
|
|
16
|
+
# placeholder_alt - String, placeholder in alternative language
|
|
17
|
+
# print_on_invoice - Boolean, show on invoices
|
|
18
|
+
# print_on_offer - Boolean, show on offers
|
|
19
|
+
# print_on_timesheet - Boolean, show on timesheets
|
|
20
|
+
# notification_enabled - Boolean, send notification for Date fields
|
|
21
|
+
# api_only - Boolean, hide from UI (API access only)
|
|
22
|
+
# defaults - Array, options for Select/MultiSelect types
|
|
23
|
+
#
|
|
24
|
+
# == Read-only attributes:
|
|
25
|
+
# id, name_alt, created_at, updated_at
|
|
26
|
+
#
|
|
27
|
+
# == Example:
|
|
28
|
+
# # Create a dropdown field
|
|
29
|
+
# moco.custom_properties.create(
|
|
30
|
+
# name: "Project Type",
|
|
31
|
+
# kind: "Select",
|
|
32
|
+
# entity: "Project",
|
|
33
|
+
# defaults: ["Website", "Mobile App", "API Integration"],
|
|
34
|
+
# print_on_invoice: true
|
|
35
|
+
# )
|
|
36
|
+
#
|
|
37
|
+
# == Note:
|
|
38
|
+
# `kind` and `entity` cannot be changed after creation.
|
|
39
|
+
#
|
|
40
|
+
class CustomProperty < BaseEntity
|
|
41
|
+
def self.entity_path
|
|
42
|
+
"account/custom_properties"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def to_s
|
|
46
|
+
name.to_s
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
data/lib/moco/entities/deal.rb
CHANGED
|
@@ -1,8 +1,44 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module MOCO
|
|
4
|
-
# Represents a MOCO deal
|
|
5
|
-
#
|
|
4
|
+
# Represents a MOCO deal/lead
|
|
5
|
+
#
|
|
6
|
+
# == Required attributes for create:
|
|
7
|
+
# name - String, deal name (e.g., "Website Relaunch")
|
|
8
|
+
# currency - String, 3-letter code (e.g., "EUR", "USD")
|
|
9
|
+
# money - Float/Integer, deal value (e.g., 25000)
|
|
10
|
+
# reminder_date - String, "YYYY-MM-DD" format for follow-up
|
|
11
|
+
# user_id - Integer, responsible user ID
|
|
12
|
+
# deal_category_id - Integer, deal category/stage ID
|
|
13
|
+
#
|
|
14
|
+
# == Optional attributes:
|
|
15
|
+
# company_id - Integer, associated company ID
|
|
16
|
+
# person_id - Integer, associated contact ID
|
|
17
|
+
# info - String, additional information
|
|
18
|
+
# status - String, one of: "potential", "pending", "won", "lost", "dropped"
|
|
19
|
+
# (default: "pending")
|
|
20
|
+
# closed_on - String, "YYYY-MM-DD" when deal was closed
|
|
21
|
+
# service_period_from - String, "YYYY-MM-DD" (must be 1st of month)
|
|
22
|
+
# service_period_to - String, "YYYY-MM-DD" (must be last of month)
|
|
23
|
+
# tags - Array of Strings, e.g., ["Important", "Q1"]
|
|
24
|
+
# custom_properties - Hash, e.g., {"Source": "Website"}
|
|
25
|
+
#
|
|
26
|
+
# == Read-only attributes (returned by API):
|
|
27
|
+
# id, user (Hash), company (Hash), person (Hash), category (Hash),
|
|
28
|
+
# created_at, updated_at
|
|
29
|
+
#
|
|
30
|
+
# == Example:
|
|
31
|
+
# moco.deals.create(
|
|
32
|
+
# name: "New Website Project",
|
|
33
|
+
# currency: "EUR",
|
|
34
|
+
# money: 50000,
|
|
35
|
+
# reminder_date: "2024-02-01",
|
|
36
|
+
# user_id: 123,
|
|
37
|
+
# deal_category_id: 456,
|
|
38
|
+
# company_id: 789,
|
|
39
|
+
# status: "pending"
|
|
40
|
+
# )
|
|
41
|
+
#
|
|
6
42
|
class Deal < BaseEntity
|
|
7
43
|
# Associations
|
|
8
44
|
def company
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents a MOCO deal category/stage (Akquise-Stufen)
|
|
5
|
+
#
|
|
6
|
+
# == Required attributes for create:
|
|
7
|
+
# name - String, category name (e.g., "Contact", "Qualified", "Proposal")
|
|
8
|
+
# probability - Integer, win probability percentage (0-100)
|
|
9
|
+
#
|
|
10
|
+
# == Read-only attributes:
|
|
11
|
+
# id, created_at, updated_at
|
|
12
|
+
#
|
|
13
|
+
# == Example:
|
|
14
|
+
# moco.deal_categories.create(
|
|
15
|
+
# name: "Qualified Lead",
|
|
16
|
+
# probability: 25
|
|
17
|
+
# )
|
|
18
|
+
#
|
|
19
|
+
# == Note:
|
|
20
|
+
# Categories cannot be deleted if deals are using them.
|
|
21
|
+
#
|
|
22
|
+
class DealCategory < BaseEntity
|
|
23
|
+
def to_s
|
|
24
|
+
name.to_s
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents a MOCO user employment/work schedule record
|
|
5
|
+
# Access via: moco.employments.where(user_id: 123) or user.employments
|
|
6
|
+
#
|
|
7
|
+
# == Required attributes for create:
|
|
8
|
+
# user_id - Integer, the user this employment belongs to
|
|
9
|
+
# pattern - Hash, weekly work schedule:
|
|
10
|
+
# { "am": [0, 4, 4, 4, 4], "pm": [0, 4, 4, 4, 4] }
|
|
11
|
+
# Arrays represent Mon-Fri morning/afternoon hours
|
|
12
|
+
#
|
|
13
|
+
# == Optional attributes:
|
|
14
|
+
# from - String, "YYYY-MM-DD" when employment starts (default: today)
|
|
15
|
+
# to - String, "YYYY-MM-DD" when employment ends (null = ongoing)
|
|
16
|
+
#
|
|
17
|
+
# == Read-only attributes:
|
|
18
|
+
# id, weekly_target_hours, user (Hash), created_at, updated_at
|
|
19
|
+
#
|
|
20
|
+
# == Example:
|
|
21
|
+
# # Create full-time employment (8h/day Mon-Fri)
|
|
22
|
+
# moco.employments.create(
|
|
23
|
+
# user_id: 123,
|
|
24
|
+
# pattern: {
|
|
25
|
+
# am: [4, 4, 4, 4, 4],
|
|
26
|
+
# pm: [4, 4, 4, 4, 4]
|
|
27
|
+
# },
|
|
28
|
+
# from: "2024-01-01"
|
|
29
|
+
# )
|
|
30
|
+
#
|
|
31
|
+
# # Create part-time (4h/day Tue-Thu)
|
|
32
|
+
# moco.employments.create(
|
|
33
|
+
# user_id: 123,
|
|
34
|
+
# pattern: {
|
|
35
|
+
# am: [0, 4, 4, 4, 0],
|
|
36
|
+
# pm: [0, 0, 0, 0, 0]
|
|
37
|
+
# },
|
|
38
|
+
# from: "2024-01-01"
|
|
39
|
+
# )
|
|
40
|
+
#
|
|
41
|
+
class Employment < BaseEntity
|
|
42
|
+
def self.entity_path
|
|
43
|
+
"users/employments"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Associations
|
|
47
|
+
def user
|
|
48
|
+
association(:user)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def to_s
|
|
52
|
+
"Employment ##{id} (#{from} - #{self.to || 'present'})"
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -1,8 +1,43 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module MOCO
|
|
4
|
-
# Represents a MOCO expense
|
|
5
|
-
#
|
|
4
|
+
# Represents a MOCO project expense (additional service)
|
|
5
|
+
# Expenses are typically accessed via project: project.expenses.create(...)
|
|
6
|
+
#
|
|
7
|
+
# == Required attributes for create:
|
|
8
|
+
# date - String, "YYYY-MM-DD" expense date
|
|
9
|
+
# title - String, expense title (e.g., "Hosting XS")
|
|
10
|
+
# quantity - Float/Integer, quantity (e.g., 3)
|
|
11
|
+
# unit - String, unit label (e.g., "months", "pieces", "hours")
|
|
12
|
+
# unit_price - Float, price per unit charged to customer
|
|
13
|
+
# unit_cost - Float, cost per unit (your cost)
|
|
14
|
+
#
|
|
15
|
+
# == Optional attributes:
|
|
16
|
+
# description - String, detailed description
|
|
17
|
+
# billable - Boolean, whether expense is billable (default: true)
|
|
18
|
+
# budget_relevant - Boolean, whether counts toward budget (default: false)
|
|
19
|
+
# service_period_from - String, "YYYY-MM-DD" service period start
|
|
20
|
+
# service_period_to - String, "YYYY-MM-DD" service period end
|
|
21
|
+
# user_id - Integer, responsible user ID (default: current user)
|
|
22
|
+
# custom_properties - Hash, e.g., {"Type": "Infrastructure"}
|
|
23
|
+
# file - Hash, { filename: "receipt.pdf", base64: "..." }
|
|
24
|
+
#
|
|
25
|
+
# == Read-only attributes:
|
|
26
|
+
# id, price, cost, currency, billed, invoice_id, project (Hash),
|
|
27
|
+
# company (Hash), created_at, updated_at
|
|
28
|
+
#
|
|
29
|
+
# == Example:
|
|
30
|
+
# project = moco.projects.find(123)
|
|
31
|
+
# project.expenses.create(
|
|
32
|
+
# date: "2024-01-15",
|
|
33
|
+
# title: "Cloud Hosting",
|
|
34
|
+
# quantity: 1,
|
|
35
|
+
# unit: "month",
|
|
36
|
+
# unit_price: 99.0,
|
|
37
|
+
# unit_cost: 49.0,
|
|
38
|
+
# billable: true
|
|
39
|
+
# )
|
|
40
|
+
#
|
|
6
41
|
class Expense < BaseEntity
|
|
7
42
|
# Override entity_path to use the global expenses endpoint
|
|
8
43
|
# Note: Expenses can also be accessed via projects/{id}/expenses
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents a MOCO expense template (Zusatzleistungs-Katalog)
|
|
5
|
+
# Pre-defined templates for project additional services
|
|
6
|
+
#
|
|
7
|
+
# == Required attributes for create:
|
|
8
|
+
# title - String, template name (e.g., "Hosting L")
|
|
9
|
+
# unit - String, unit type (e.g., "month", "hours", "pieces")
|
|
10
|
+
# unit_price - Float, price per unit
|
|
11
|
+
# currency - String, currency code (e.g., "EUR")
|
|
12
|
+
#
|
|
13
|
+
# == Optional attributes:
|
|
14
|
+
# description - String, detailed description
|
|
15
|
+
# unit_cost - Float, internal cost per unit
|
|
16
|
+
#
|
|
17
|
+
# == Read-only attributes:
|
|
18
|
+
# id, revenue_category (Hash), created_at, updated_at
|
|
19
|
+
#
|
|
20
|
+
# == Example:
|
|
21
|
+
# moco.expense_templates.create(
|
|
22
|
+
# title: "Monthly Hosting",
|
|
23
|
+
# description: "Web hosting with monitoring and backup",
|
|
24
|
+
# unit: "month",
|
|
25
|
+
# unit_price: 50.0,
|
|
26
|
+
# unit_cost: 30.0,
|
|
27
|
+
# currency: "EUR"
|
|
28
|
+
# )
|
|
29
|
+
#
|
|
30
|
+
class ExpenseTemplate < BaseEntity
|
|
31
|
+
def self.entity_path
|
|
32
|
+
"account/expense_templates"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def to_s
|
|
36
|
+
name.to_s
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents a MOCO fixed cost entry (Fixkosten)
|
|
5
|
+
# Read-only access to company fixed costs for reporting
|
|
6
|
+
#
|
|
7
|
+
# == Read-only attributes:
|
|
8
|
+
# id, title, description, costs (Array of monthly amounts),
|
|
9
|
+
# created_at, updated_at
|
|
10
|
+
#
|
|
11
|
+
# == Costs array format:
|
|
12
|
+
# [{ year: 2024, month: 1, amount: 50000.0 }, ...]
|
|
13
|
+
#
|
|
14
|
+
# == Filtering:
|
|
15
|
+
# moco.fixed_costs.where(year: 2024)
|
|
16
|
+
#
|
|
17
|
+
# == Note:
|
|
18
|
+
# Fixed costs are configured in MOCO's admin interface.
|
|
19
|
+
# This endpoint provides read-only access for reporting.
|
|
20
|
+
#
|
|
21
|
+
class FixedCost < BaseEntity
|
|
22
|
+
def self.entity_path
|
|
23
|
+
"account/fixed_costs"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_s
|
|
27
|
+
name.to_s
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -1,8 +1,39 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module MOCO
|
|
4
|
-
# Represents a MOCO holiday
|
|
5
|
-
#
|
|
4
|
+
# Represents a MOCO user holiday/vacation entitlement record
|
|
5
|
+
# German: "Urlaubsanspruch"
|
|
6
|
+
#
|
|
7
|
+
# == Required attributes for create:
|
|
8
|
+
# user_id - Integer, the user this holiday entitlement belongs to
|
|
9
|
+
# year - Integer, the year (e.g., 2024)
|
|
10
|
+
# title - String, description (e.g., "Urlaubsanspruch 80%")
|
|
11
|
+
# days - Integer/Float, number of vacation days entitled
|
|
12
|
+
#
|
|
13
|
+
# == Optional attributes:
|
|
14
|
+
# creator_id - Integer, user who created this record
|
|
15
|
+
#
|
|
16
|
+
# == Read-only attributes:
|
|
17
|
+
# id, hours (auto-calculated from days), user (Hash), creator (Hash),
|
|
18
|
+
# created_at, updated_at
|
|
19
|
+
#
|
|
20
|
+
# == Example:
|
|
21
|
+
# # Create holiday entitlement for a user
|
|
22
|
+
# moco.holidays.create(
|
|
23
|
+
# user_id: 123,
|
|
24
|
+
# year: 2024,
|
|
25
|
+
# title: "Annual vacation entitlement",
|
|
26
|
+
# days: 25
|
|
27
|
+
# )
|
|
28
|
+
#
|
|
29
|
+
# == Filtering:
|
|
30
|
+
# moco.holidays.where(year: 2024)
|
|
31
|
+
# moco.holidays.where(user_id: 123)
|
|
32
|
+
#
|
|
33
|
+
# == Note:
|
|
34
|
+
# Holiday days are converted to hours using the user's daily hours setting.
|
|
35
|
+
# 10 days at 8h/day = 80 hours, 10 days at 5h/day = 50 hours.
|
|
36
|
+
#
|
|
6
37
|
class Holiday < BaseEntity
|
|
7
38
|
# Override entity_path to match API path
|
|
8
39
|
def self.entity_path
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents MOCO hourly rates (Stundensätze)
|
|
5
|
+
# Read-only access to billing rates by task and user
|
|
6
|
+
#
|
|
7
|
+
# == Read-only structure:
|
|
8
|
+
# defaults_rates - Array of default rates per currency
|
|
9
|
+
# tasks - Array of tasks with their rates per currency
|
|
10
|
+
# users - Array of users with their rates per currency
|
|
11
|
+
#
|
|
12
|
+
# == Rate format:
|
|
13
|
+
# { currency: "EUR", hourly_rate: 150.0 }
|
|
14
|
+
#
|
|
15
|
+
# == Filtering:
|
|
16
|
+
# moco.hourly_rates.where(company_id: 123) # customer-specific rates
|
|
17
|
+
# moco.hourly_rates.where(include_archived_users: true)
|
|
18
|
+
#
|
|
19
|
+
# == Note:
|
|
20
|
+
# Hourly rates are configured in MOCO's admin interface.
|
|
21
|
+
# This endpoint provides read-only access.
|
|
22
|
+
# Without company_id, returns global default rates.
|
|
23
|
+
#
|
|
24
|
+
class HourlyRate < BaseEntity
|
|
25
|
+
def self.entity_path
|
|
26
|
+
"account/hourly_rates"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_s
|
|
30
|
+
"#{name} - #{rate}"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents MOCO internal hourly rates (Interne Stundensätze)
|
|
5
|
+
# Internal cost rates per user for profitability calculations
|
|
6
|
+
#
|
|
7
|
+
# == Read-only structure (per user):
|
|
8
|
+
# id, full_name, rates (Array by year)
|
|
9
|
+
#
|
|
10
|
+
# == Rate format:
|
|
11
|
+
# { year: 2024, rate: 120.0 }
|
|
12
|
+
#
|
|
13
|
+
# == Filtering:
|
|
14
|
+
# moco.internal_hourly_rates.where(years: "2024")
|
|
15
|
+
# moco.internal_hourly_rates.where(years: "2023,2024")
|
|
16
|
+
# moco.internal_hourly_rates.where(unit_id: 123)
|
|
17
|
+
# moco.internal_hourly_rates.where(include_archived: true)
|
|
18
|
+
#
|
|
19
|
+
# == Updating rates:
|
|
20
|
+
# Use PATCH with year and rates array:
|
|
21
|
+
# { year: 2024, rates: [{ user_id: 123, rate: 140.0 }] }
|
|
22
|
+
#
|
|
23
|
+
class InternalHourlyRate < BaseEntity
|
|
24
|
+
def self.entity_path
|
|
25
|
+
"account/internal_hourly_rates"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def to_s
|
|
29
|
+
"#{name} - #{rate}"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -2,7 +2,60 @@
|
|
|
2
2
|
|
|
3
3
|
module MOCO
|
|
4
4
|
# Represents a MOCO invoice
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
|
+
# == Required attributes for create:
|
|
7
|
+
# customer_id - Integer, customer company ID
|
|
8
|
+
# recipient_address - String, full address (use \n for line breaks)
|
|
9
|
+
# date - String, "YYYY-MM-DD" invoice date
|
|
10
|
+
# due_date - String, "YYYY-MM-DD" payment due date
|
|
11
|
+
# title - String, invoice title (e.g., "Invoice")
|
|
12
|
+
# tax - Float, tax rate percentage (e.g., 19.0)
|
|
13
|
+
# currency - String, 3-letter code (e.g., "EUR")
|
|
14
|
+
# items - Array of Hashes, invoice line items (see below)
|
|
15
|
+
#
|
|
16
|
+
# == Item types (for items array):
|
|
17
|
+
# { type: "title", title: "Section Title" }
|
|
18
|
+
# { type: "description", description: "Some description text" }
|
|
19
|
+
# { type: "item", title: "Service", quantity: 10, unit: "h", unit_price: 150.0 }
|
|
20
|
+
# { type: "item", title: "Fixed Fee", net_total: 500.0 } # lump sum
|
|
21
|
+
# { type: "subtotal" }
|
|
22
|
+
# { type: "separator" }
|
|
23
|
+
# { type: "page-break" }
|
|
24
|
+
#
|
|
25
|
+
# == Optional attributes:
|
|
26
|
+
# project_id - Integer, associated project ID
|
|
27
|
+
# status - String, "created" or "draft" (default: "created")
|
|
28
|
+
# service_period_from - String, "YYYY-MM-DD"
|
|
29
|
+
# service_period_to - String, "YYYY-MM-DD"
|
|
30
|
+
# change_address - String, "invoice", "project", or "customer"
|
|
31
|
+
# salutation - String, greeting text (HTML allowed)
|
|
32
|
+
# footer - String, footer text (HTML allowed)
|
|
33
|
+
# discount - Float, discount percentage
|
|
34
|
+
# cash_discount - Float, early payment discount percentage
|
|
35
|
+
# cash_discount_days - Integer, days for early payment discount
|
|
36
|
+
# tags - Array of Strings
|
|
37
|
+
# custom_properties - Hash
|
|
38
|
+
#
|
|
39
|
+
# == Read-only attributes:
|
|
40
|
+
# id, identifier, status, net_total, gross_total, payments, reminders,
|
|
41
|
+
# created_at, updated_at
|
|
42
|
+
#
|
|
43
|
+
# == Example:
|
|
44
|
+
# moco.invoices.create(
|
|
45
|
+
# customer_id: 123456,
|
|
46
|
+
# recipient_address: "Acme Corp\n123 Main St\n12345 City",
|
|
47
|
+
# date: "2024-01-15",
|
|
48
|
+
# due_date: "2024-02-15",
|
|
49
|
+
# title: "Invoice",
|
|
50
|
+
# tax: 19.0,
|
|
51
|
+
# currency: "EUR",
|
|
52
|
+
# items: [
|
|
53
|
+
# { type: "title", title: "Services January 2024" },
|
|
54
|
+
# { type: "item", title: "Development", quantity: 40, unit: "h", unit_price: 150.0 },
|
|
55
|
+
# { type: "item", title: "Project Management", quantity: 8, unit: "h", unit_price: 120.0 }
|
|
56
|
+
# ]
|
|
57
|
+
# )
|
|
58
|
+
#
|
|
6
59
|
class Invoice < BaseEntity
|
|
7
60
|
# Instance methods for invoice-specific operations
|
|
8
61
|
def update_status(status)
|
|
@@ -37,6 +90,33 @@ module MOCO
|
|
|
37
90
|
self
|
|
38
91
|
end
|
|
39
92
|
|
|
93
|
+
# Get attachments for this invoice
|
|
94
|
+
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
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Fetches payments for this invoice
|
|
111
|
+
def payments
|
|
112
|
+
MOCO::NestedCollectionProxy.new(client, self, :payments, "InvoicePayment")
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Fetches reminders for this invoice
|
|
116
|
+
def reminders
|
|
117
|
+
MOCO::NestedCollectionProxy.new(client, self, :reminders, "InvoiceReminder")
|
|
118
|
+
end
|
|
119
|
+
|
|
40
120
|
# Associations
|
|
41
121
|
def company
|
|
42
122
|
association(:customer, "Company")
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MOCO
|
|
4
|
+
# Represents a MOCO invoice bookkeeping export (Buchhaltungsexporte)
|
|
5
|
+
# Exports invoice data for accounting systems
|
|
6
|
+
#
|
|
7
|
+
# == Read-only attributes:
|
|
8
|
+
# id, from, to, file_url, user (Hash),
|
|
9
|
+
# created_at, updated_at
|
|
10
|
+
#
|
|
11
|
+
# == Filtering:
|
|
12
|
+
# moco.invoice_bookkeeping_exports.all
|
|
13
|
+
# moco.invoice_bookkeeping_exports.where(from: "2024-01-01", to: "2024-01-31")
|
|
14
|
+
#
|
|
15
|
+
# == Note:
|
|
16
|
+
# Bookkeeping exports are generated via MOCO's finance interface.
|
|
17
|
+
# This endpoint provides read-only access to export records.
|
|
18
|
+
#
|
|
19
|
+
class InvoiceBookkeepingExport < BaseEntity
|
|
20
|
+
# Custom path since it's nested under invoices
|
|
21
|
+
def self.entity_path
|
|
22
|
+
"invoices/bookkeeping_exports"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def user
|
|
26
|
+
association(:user, "User")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_s
|
|
30
|
+
"InvoiceBookkeepingExport #{id} (#{from} - #{to})"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|