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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -1
  3. data/Gemfile.lock +44 -40
  4. data/README.md +53 -24
  5. data/lib/moco/client.rb +58 -0
  6. data/lib/moco/connection.rb +45 -22
  7. data/lib/moco/entities/activity.rb +31 -1
  8. data/lib/moco/entities/catalog_service.rb +54 -0
  9. data/lib/moco/entities/comment.rb +61 -0
  10. data/lib/moco/entities/company.rb +57 -2
  11. data/lib/moco/entities/contact.rb +56 -0
  12. data/lib/moco/entities/custom_property.rb +49 -0
  13. data/lib/moco/entities/deal.rb +38 -2
  14. data/lib/moco/entities/deal_category.rb +27 -0
  15. data/lib/moco/entities/employment.rb +55 -0
  16. data/lib/moco/entities/expense.rb +37 -2
  17. data/lib/moco/entities/expense_template.rb +39 -0
  18. data/lib/moco/entities/fixed_cost.rb +30 -0
  19. data/lib/moco/entities/holiday.rb +33 -2
  20. data/lib/moco/entities/hourly_rate.rb +33 -0
  21. data/lib/moco/entities/internal_hourly_rate.rb +32 -0
  22. data/lib/moco/entities/invoice.rb +81 -1
  23. data/lib/moco/entities/invoice_bookkeeping_export.rb +33 -0
  24. data/lib/moco/entities/invoice_payment.rb +51 -0
  25. data/lib/moco/entities/invoice_reminder.rb +51 -0
  26. data/lib/moco/entities/offer.rb +122 -0
  27. data/lib/moco/entities/offer_approval.rb +42 -0
  28. data/lib/moco/entities/payment_schedule.rb +48 -0
  29. data/lib/moco/entities/planning_entry.rb +43 -2
  30. data/lib/moco/entities/presence.rb +34 -2
  31. data/lib/moco/entities/profile.rb +24 -0
  32. data/lib/moco/entities/project.rb +76 -10
  33. data/lib/moco/entities/project_contract.rb +50 -0
  34. data/lib/moco/entities/project_group.rb +38 -0
  35. data/lib/moco/entities/purchase.rb +90 -0
  36. data/lib/moco/entities/purchase_bookkeeping_export.rb +34 -0
  37. data/lib/moco/entities/purchase_budget.rb +47 -0
  38. data/lib/moco/entities/purchase_category.rb +38 -0
  39. data/lib/moco/entities/purchase_draft.rb +25 -0
  40. data/lib/moco/entities/purchase_payment.rb +51 -0
  41. data/lib/moco/entities/receipt.rb +55 -0
  42. data/lib/moco/entities/recurring_expense.rb +55 -0
  43. data/lib/moco/entities/reports/absences.rb +16 -0
  44. data/lib/moco/entities/reports/cashflow.rb +16 -0
  45. data/lib/moco/entities/reports/finance.rb +16 -0
  46. data/lib/moco/entities/reports/utilization.rb +16 -0
  47. data/lib/moco/entities/schedule.rb +39 -2
  48. data/lib/moco/entities/tag.rb +30 -0
  49. data/lib/moco/entities/tagging.rb +27 -0
  50. data/lib/moco/entities/task.rb +25 -2
  51. data/lib/moco/entities/task_template.rb +38 -0
  52. data/lib/moco/entities/unit.rb +36 -0
  53. data/lib/moco/entities/user.rb +50 -2
  54. data/lib/moco/entities/user_role.rb +29 -0
  55. data/lib/moco/entities/vat_code_purchase.rb +29 -0
  56. data/lib/moco/entities/vat_code_sale.rb +29 -0
  57. data/lib/moco/entities/web_hook.rb +32 -2
  58. data/lib/moco/entities/work_time_adjustment.rb +51 -0
  59. data/lib/moco/version.rb +1 -1
  60. data/lib/moco.rb +51 -1
  61. data/moco.gemspec +38 -0
  62. metadata +47 -8
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MOCO
4
+ # Represents a MOCO purchase/expense (Ausgaben)
5
+ #
6
+ # == Required attributes for create:
7
+ # date - String, "YYYY-MM-DD" format
8
+ # currency - String, valid currency code (e.g., "EUR", "CHF", "USD")
9
+ # payment_method - String, one of:
10
+ # "bank_transfer", "direct_debit", "credit_card",
11
+ # "paypal", "cash", "bank_transfer_swiss_qr_esr"
12
+ # items - Array of item hashes (at least one required):
13
+ # { title: "Item", total: 100.0, tax: 7.7, tax_included: true }
14
+ #
15
+ # == Optional attributes:
16
+ # title - String, purchase title (auto-generated from items if omitted)
17
+ # due_date - String, "YYYY-MM-DD" payment due date
18
+ # service_period_from - String, "YYYY-MM-DD" service period start
19
+ # service_period_to - String, "YYYY-MM-DD" service period end
20
+ # status - String, "pending" (Inbox) or "archived" (Archive)
21
+ # company_id - Integer, supplier company ID
22
+ # user_id - Integer, responsible user ID
23
+ # receipt_identifier - String, supplier's invoice number
24
+ # info - String, free text notes
25
+ # iban - String, bank account for payment
26
+ # reference - String, payment reference
27
+ # custom_property_values - Hash, custom field values
28
+ # tags - Array of Strings, labels
29
+ # file - Hash, { filename: "doc.pdf", base64: "..." }
30
+ #
31
+ # == Item attributes:
32
+ # title - String, item description
33
+ # total - Float, item total amount
34
+ # tax - Float, tax percentage (e.g., 7.7)
35
+ # tax_included - Boolean, whether total includes tax
36
+ # category_id - Integer, purchase category ID
37
+ #
38
+ # == Read-only attributes:
39
+ # id, identifier, net_total, gross_total, payments (Array),
40
+ # approval_status, file_url, company (Hash), user (Hash),
41
+ # created_at, updated_at
42
+ #
43
+ # == Example:
44
+ # moco.purchases.create(
45
+ # date: "2024-01-15",
46
+ # currency: "EUR",
47
+ # payment_method: "bank_transfer",
48
+ # company_id: 456,
49
+ # items: [
50
+ # { title: "Office supplies", total: 119.0, tax: 19.0, tax_included: true }
51
+ # ],
52
+ # tags: ["Office"]
53
+ # )
54
+ #
55
+ class Purchase < BaseEntity
56
+ # Assign purchase to a project expense
57
+ def assign_to_project(project_id:, project_expense_id: nil)
58
+ payload = { project_id: }
59
+ payload[:project_expense_id] = project_expense_id if project_expense_id
60
+
61
+ client.post("purchases/#{id}/assign_to_project", payload)
62
+ reload
63
+ end
64
+
65
+ # Update purchase status (pending/archived)
66
+ def update_status(status)
67
+ client.patch("purchases/#{id}/update_status", { status: })
68
+ reload
69
+ end
70
+
71
+ # Store/upload a document for this purchase
72
+ def store_document(file_data)
73
+ client.patch("purchases/#{id}/store_document", file_data)
74
+ self
75
+ end
76
+
77
+ # Associations
78
+ def company
79
+ association(:company)
80
+ end
81
+
82
+ def user
83
+ association(:user)
84
+ end
85
+
86
+ def to_s
87
+ "#{title} (#{date})"
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MOCO
4
+ # Represents a MOCO purchase bookkeeping export
5
+ # (Ausgaben / Buchhaltungsexporte)
6
+ # Exports purchase data for accounting systems
7
+ #
8
+ # == Read-only attributes:
9
+ # id, from, to, file_url, user (Hash),
10
+ # created_at, updated_at
11
+ #
12
+ # == Filtering:
13
+ # moco.purchase_bookkeeping_exports.all
14
+ # moco.purchase_bookkeeping_exports.where(from: "2024-01-01", to: "2024-01-31")
15
+ #
16
+ # == Note:
17
+ # Bookkeeping exports are generated via MOCO's finance interface.
18
+ # This endpoint provides read-only access to export records.
19
+ #
20
+ class PurchaseBookkeepingExport < BaseEntity
21
+ # Custom path since it's nested under purchases
22
+ def self.entity_path
23
+ "purchases/bookkeeping_exports"
24
+ end
25
+
26
+ def user
27
+ association(:user, "User")
28
+ end
29
+
30
+ def to_s
31
+ "PurchaseBookkeepingExport #{id} (#{from} - #{to})"
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MOCO
4
+ # Represents a MOCO purchase budget (Ausgaben – Budgets)
5
+ # Read-only budget tracking for expense categories
6
+ #
7
+ # == Read-only attributes:
8
+ # id, title, year, target, exhausted, remaining,
9
+ # created_at, updated_at
10
+ #
11
+ # == Helper methods:
12
+ # remaining_percentage - Percentage of budget remaining
13
+ # exhausted_percentage - Percentage of budget used
14
+ #
15
+ # == Example:
16
+ # budgets = moco.purchase_budgets.all
17
+ # budgets.each do |budget|
18
+ # puts "#{budget.title}: #{budget.remaining_percentage}% remaining"
19
+ # end
20
+ #
21
+ # == Note:
22
+ # Purchase budgets are configured in MOCO's admin interface.
23
+ # This endpoint provides read-only access for tracking.
24
+ #
25
+ class PurchaseBudget < BaseEntity
26
+ # Custom path since it's nested under purchases
27
+ def self.entity_path
28
+ "purchases/budgets"
29
+ end
30
+
31
+ def to_s
32
+ "PurchaseBudget #{id}: #{title} (#{year})"
33
+ end
34
+
35
+ def remaining_percentage
36
+ return 0 if target.to_f.zero?
37
+
38
+ (remaining.to_f / target.to_f * 100).round(1)
39
+ end
40
+
41
+ def exhausted_percentage
42
+ return 0 if target.to_f.zero?
43
+
44
+ (exhaused.to_f / target.to_f * 100).round(1)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MOCO
4
+ # Represents a MOCO purchase category (Ausgaben – Kategorien)
5
+ # Read-only expense categories for organizing purchases
6
+ #
7
+ # == Read-only attributes:
8
+ # id, name, credit_account, active, created_at, updated_at
9
+ #
10
+ # == Example:
11
+ # # List all categories
12
+ # moco.purchase_categories.all
13
+ #
14
+ # # Use category when creating purchase
15
+ # moco.purchases.create(
16
+ # # ... other fields ...
17
+ # items: [{
18
+ # title: "Travel",
19
+ # total: 250.0,
20
+ # tax: 7.7,
21
+ # category_id: 123 # from purchase_categories
22
+ # }]
23
+ # )
24
+ #
25
+ # == Note:
26
+ # Purchase categories are configured in MOCO's admin interface.
27
+ # This endpoint provides read-only access.
28
+ #
29
+ class PurchaseCategory < BaseEntity
30
+ def self.entity_path
31
+ "purchases/categories"
32
+ end
33
+
34
+ def to_s
35
+ name.to_s
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MOCO
4
+ # Represents a MOCO purchase draft
5
+ # Auto-created draft purchases from document scanning
6
+ #
7
+ # == Read-only attributes:
8
+ # id, title, date, company (Hash), file_url,
9
+ # items (Array), created_at, updated_at
10
+ #
11
+ # == Note:
12
+ # Purchase drafts are created automatically when documents
13
+ # are uploaded/scanned in MOCO's inbox.
14
+ # Convert to actual purchases via the MOCO interface.
15
+ #
16
+ class PurchaseDraft < BaseEntity
17
+ def self.entity_path
18
+ "purchases/drafts"
19
+ end
20
+
21
+ def to_s
22
+ "Draft ##{id}"
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MOCO
4
+ # Represents a MOCO purchase payment record (Ausgaben / Zahlungen)
5
+ # For tracking payments made for purchases
6
+ #
7
+ # == Required attributes for create:
8
+ # date - String, "YYYY-MM-DD" payment date
9
+ # total - Float, payment amount
10
+ #
11
+ # == Optional attributes:
12
+ # purchase_id - Integer, purchase being paid (required unless description set)
13
+ # description - String, payment description (required if no purchase_id)
14
+ #
15
+ # == Read-only attributes:
16
+ # id, purchase (Hash), created_at, updated_at
17
+ #
18
+ # == Example:
19
+ # moco.purchase_payments.create(
20
+ # date: "2024-01-20",
21
+ # purchase_id: 456,
22
+ # total: 1500.0
23
+ # )
24
+ #
25
+ # == Bulk create:
26
+ # moco.post("purchases/payments/bulk", {
27
+ # bulk_data: [
28
+ # { date: "2024-01-20", purchase_id: 123, total: 500 },
29
+ # { date: "2024-01-21", description: "Salaries", total: 10000 }
30
+ # ]
31
+ # })
32
+ #
33
+ # == Filtering:
34
+ # moco.purchase_payments.where(purchase_id: 456)
35
+ # moco.purchase_payments.where(date_from: "2024-01-01", date_to: "2024-01-31")
36
+ #
37
+ class PurchasePayment < BaseEntity
38
+ # Custom path since it's nested under purchases
39
+ def self.entity_path
40
+ "purchases/payments"
41
+ end
42
+
43
+ def purchase
44
+ association(:purchase, "Purchase")
45
+ end
46
+
47
+ def to_s
48
+ "PurchasePayment #{id}: #{total} on #{date}"
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MOCO
4
+ # Represents a MOCO receipt/expense claim (Spesen)
5
+ #
6
+ # == Required attributes for create:
7
+ # date - String, "YYYY-MM-DD" format
8
+ # title - String, receipt description (e.g., "Team lunch")
9
+ # currency - String, valid currency code (e.g., "EUR", "CHF")
10
+ # items - Array of item hashes (at least one required):
11
+ # { vat_code_id: 186, gross_total: 99.90 }
12
+ #
13
+ # == Optional attributes:
14
+ # project_id - Integer, project to associate with
15
+ # info - String, additional notes
16
+ # billable - Boolean, whether expense is billable to customer
17
+ # attachment - Hash, { filename: "receipt.pdf", base64: "..." }
18
+ #
19
+ # == Item attributes:
20
+ # vat_code_id - Integer, VAT code ID (required)
21
+ # gross_total - Float, total amount including tax (required)
22
+ # purchase_category_id - Integer, expense category
23
+ #
24
+ # == Read-only attributes:
25
+ # id, pending, user (Hash), project (Hash), refund_request (Hash),
26
+ # attachment_url, created_at, updated_at
27
+ #
28
+ # == Example:
29
+ # moco.receipts.create(
30
+ # date: "2024-01-15",
31
+ # title: "Client lunch",
32
+ # currency: "EUR",
33
+ # project_id: 123,
34
+ # billable: true,
35
+ # items: [
36
+ # { vat_code_id: 186, gross_total: 85.50 }
37
+ # ]
38
+ # )
39
+ #
40
+ # == Filtering:
41
+ # moco.receipts.where(from: "2024-01-01", to: "2024-01-31")
42
+ # moco.receipts.where(project_id: 123)
43
+ # moco.receipts.where(user_id: 456)
44
+ #
45
+ class Receipt < BaseEntity
46
+ # Associations
47
+ def user
48
+ association(:user)
49
+ end
50
+
51
+ def to_s
52
+ "#{title} (#{date})"
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MOCO
4
+ # Represents a MOCO project recurring expense
5
+ # (Wiederkehrende Zusatzleistungen) for ongoing services like hosting
6
+ #
7
+ # == Required attributes for create:
8
+ # start_date - String, "YYYY-MM-DD" when recurring starts
9
+ # period - String, recurrence interval:
10
+ # "weekly", "biweekly", "monthly", "quarterly",
11
+ # "biannual", "annual"
12
+ # title - String, expense name (e.g., "Monthly Hosting")
13
+ # quantity - Float, number of units per period
14
+ # unit - String, unit type (e.g., "Server", "License")
15
+ # unit_price - Float, price per unit
16
+ # unit_cost - Float, internal cost per unit
17
+ #
18
+ # == Optional attributes:
19
+ # finish_date - String, "YYYY-MM-DD" when to stop (null = unlimited)
20
+ # description - String, detailed description
21
+ # billable - Boolean, whether to invoice (default: true)
22
+ # budget_relevant - Boolean, count toward budget (default: false)
23
+ # service_period_direction - String, "none", "forward", "backward"
24
+ # custom_properties - Hash, custom field values
25
+ #
26
+ # == Read-only attributes:
27
+ # id, price, cost, currency, recur_next_date, project (Hash),
28
+ # revenue_category (Hash), created_at, updated_at
29
+ #
30
+ # == Example:
31
+ # moco.post("projects/123/recurring_expenses", {
32
+ # start_date: "2024-01-01",
33
+ # period: "monthly",
34
+ # title: "Web Hosting",
35
+ # quantity: 1,
36
+ # unit: "Server",
37
+ # unit_price: 99.0,
38
+ # unit_cost: 50.0,
39
+ # billable: true
40
+ # })
41
+ #
42
+ # == Note:
43
+ # start_date and period cannot be modified after creation.
44
+ #
45
+ class RecurringExpense < BaseEntity
46
+ # Associations
47
+ def project
48
+ association(:project)
49
+ end
50
+
51
+ def to_s
52
+ "RecurringExpense ##{id} - #{title}"
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MOCO
4
+ module Reports
5
+ # Represents a MOCO absences report (read-only)
6
+ class Absences < BaseEntity
7
+ def self.entity_path
8
+ "report/absences"
9
+ end
10
+
11
+ def to_s
12
+ "AbsencesReport"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MOCO
4
+ module Reports
5
+ # Represents a MOCO cashflow report (read-only)
6
+ class Cashflow < BaseEntity
7
+ def self.entity_path
8
+ "report/cashflow"
9
+ end
10
+
11
+ def to_s
12
+ "CashflowReport"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MOCO
4
+ module Reports
5
+ # Represents a MOCO finance report (read-only)
6
+ class Finance < BaseEntity
7
+ def self.entity_path
8
+ "report/finance"
9
+ end
10
+
11
+ def to_s
12
+ "FinanceReport"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MOCO
4
+ module Reports
5
+ # Represents a MOCO utilization report (read-only)
6
+ class Utilization < BaseEntity
7
+ def self.entity_path
8
+ "report/utilization"
9
+ end
10
+
11
+ def to_s
12
+ "UtilizationReport"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,8 +1,45 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MOCO
4
- # Represents a MOCO schedule entry
5
- # Provides methods for schedule-specific associations
4
+ # Represents a MOCO schedule entry (absence/time-off)
5
+ # Note: For project planning, use PlanningEntry instead
6
+ #
7
+ # == Required attributes for create:
8
+ # date - String, "YYYY-MM-DD" date of absence
9
+ # absence_code - Integer, type of absence:
10
+ # 1 = unplannable absence
11
+ # 2 = public holiday
12
+ # 3 = sick day
13
+ # 4 = holiday/vacation
14
+ # 5 = other absence
15
+ #
16
+ # == Optional attributes:
17
+ # user_id - Integer, user ID (default: current user)
18
+ # am - Boolean, morning absence (default: true)
19
+ # pm - Boolean, afternoon absence (default: true)
20
+ # comment - String, comment/note
21
+ # symbol - Integer, 1-6 for half day visualization
22
+ #
23
+ # == Read-only attributes:
24
+ # id, assignment (Hash), user (Hash), created_at, updated_at
25
+ #
26
+ # == Example:
27
+ # # Full day vacation
28
+ # moco.schedules.create(
29
+ # date: "2024-01-15",
30
+ # absence_code: 4,
31
+ # user_id: 123,
32
+ # comment: "Annual leave"
33
+ # )
34
+ #
35
+ # # Half day sick (morning only)
36
+ # moco.schedules.create(
37
+ # date: "2024-01-16",
38
+ # absence_code: 3,
39
+ # am: true,
40
+ # pm: false
41
+ # )
42
+ #
6
43
  class Schedule < BaseEntity
7
44
  # Associations
8
45
  def user
@@ -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
@@ -1,8 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MOCO
4
- # Represents a MOCO task
5
- # Provides methods for task-specific associations
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