hcbv4 0.1.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.
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HCBV4
4
+ # ACH bank transfer details.
5
+ # @attr_reader recipient_name [String, nil]
6
+ # @attr_reader recipient_email [String, nil]
7
+ # @attr_reader bank_name [String, nil]
8
+ # @attr_reader account_number_last4 [String, nil] last 4 digits (requires permission)
9
+ # @attr_reader routing_number [String, nil] (requires permission)
10
+ # @attr_reader payment_for [String, nil] payment memo
11
+ # @attr_reader sender [User, nil] user who initiated the transfer
12
+ class ACHTransfer < BaseTransactionDetail
13
+ attr_reader :recipient_name, :recipient_email, :bank_name, :account_number_last4, :routing_number, :payment_for,
14
+ :sender
15
+
16
+ def initialize(id:, amount_cents: nil, memo: nil, status: nil, recipient_name: nil, recipient_email: nil,
17
+ bank_name: nil, account_number_last4: nil, routing_number: nil, payment_for: nil, sender: nil)
18
+ super(id:, amount_cents:, memo:, status:)
19
+ @recipient_name = recipient_name
20
+ @recipient_email = recipient_email
21
+ @bank_name = bank_name
22
+ @account_number_last4 = account_number_last4
23
+ @routing_number = routing_number
24
+ @payment_for = payment_for
25
+ @sender = sender
26
+ end
27
+
28
+ # @param hash [Hash] API response
29
+ # @return [ACHTransfer]
30
+ def self.from_hash(hash)
31
+ new(
32
+ id: hash["id"],
33
+ amount_cents: hash["amount_cents"],
34
+ memo: hash["memo"],
35
+ status: hash["status"],
36
+ recipient_name: hash["recipient_name"],
37
+ recipient_email: hash["recipient_email"],
38
+ bank_name: hash["bank_name"],
39
+ account_number_last4: hash["account_number_last4"],
40
+ routing_number: hash["routing_number"],
41
+ payment_for: hash["payment_for"],
42
+ sender: hash["sender"] ? User.from_hash(hash["sender"]) : nil
43
+ )
44
+ end
45
+ end
46
+
47
+ AchTransferDetails = ACHTransfer
48
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HCBV4
4
+ # Base class for transaction detail types (Transfer, AchTransfer, Check, etc.).
5
+ class BaseTransactionDetail
6
+ include TransactionType
7
+
8
+ attr_reader :id, :amount_cents, :memo, :status
9
+
10
+ def initialize(id:, amount_cents: nil, memo: nil, status: nil)
11
+ @id = id
12
+ @amount_cents = amount_cents
13
+ @memo = memo
14
+ @status = status
15
+ end
16
+
17
+ # @param hash [Hash] API response
18
+ # @return [BaseTransactionDetail]
19
+ def self.from_hash(hash)
20
+ new(
21
+ id: hash["id"],
22
+ amount_cents: hash["amount_cents"],
23
+ memo: hash["memo"],
24
+ status: hash["status"]
25
+ )
26
+ end
27
+
28
+ def ==(other)
29
+ other.is_a?(self.class) && id == other.id
30
+ end
31
+ alias eql? ==
32
+
33
+ def hash
34
+ id.hash
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HCBV4
4
+ # Card purchase details for a transaction.
5
+ # @attr_reader merchant [Merchant, nil] merchant info
6
+ # @attr_reader charge_method [String, nil] "chip", "swipe", "contactless", etc.
7
+ # @attr_reader spent_at [String, nil] ISO timestamp
8
+ # @attr_reader wallet [String, nil] "apple_pay", "google_pay", etc.
9
+ # @attr_reader card [StripeCard, nil] the card used
10
+ CardCharge = Data.define(:merchant, :charge_method, :spent_at, :wallet, :card) do
11
+ include TransactionType
12
+
13
+ # @param hash [Hash] API response
14
+ # @return [CardCharge]
15
+ def self.from_hash(hash)
16
+ new(
17
+ merchant: hash["merchant"] ? Merchant.from_hash(hash["merchant"]) : nil,
18
+ charge_method: hash["charge_method"],
19
+ spent_at: hash["spent_at"],
20
+ wallet: hash["wallet"],
21
+ card: hash["card"] ? StripeCard.from_hash(hash["card"]) : nil
22
+ )
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HCBV4
4
+ # A physical card design for personalization.
5
+ CardDesign = Data.define(:id, :name, :color, :status, :unlisted, :common, :logo_url) do
6
+ # @param hash [Hash] API response
7
+ # @return [CardDesign]
8
+ def self.from_hash(hash)
9
+ new(
10
+ id: hash["id"], name: hash["name"], color: hash["color"], status: hash["status"],
11
+ unlisted: hash["unlisted"], common: hash["common"], logo_url: hash["logo_url"]
12
+ )
13
+ end
14
+
15
+ # @return [Boolean] true if not shown in public picker
16
+ def unlisted? = !!unlisted
17
+
18
+ # @return [Boolean] true if available to all orgs
19
+ def common? = !!common
20
+ end
21
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HCBV4
4
+ # A virtual card grant with optional spending restrictions.
5
+ # Can be topped up, withdrawn, activated, or cancelled.
6
+ CardGrant = Data.define(
7
+ :id, :amount_cents, :balance_cents, :email, :status, :merchant_lock, :category_lock,
8
+ :keyword_lock, :allowed_merchants, :allowed_categories, :purpose, :one_time_use,
9
+ :pre_authorization_required, :card_id, :user, :organization, :disbursements, :_client
10
+ ) do
11
+ include Resource
12
+
13
+ # @param hash [Hash] API response
14
+ # @param client [Client, nil]
15
+ # @return [CardGrant]
16
+ def self.from_hash(hash, client: nil)
17
+ organization = hash["organization"] ? Organization.from_hash(hash["organization"]) : nil
18
+
19
+ new(
20
+ id: hash["id"],
21
+ amount_cents: hash["amount_cents"],
22
+ balance_cents: hash["balance_cents"],
23
+ email: hash["email"],
24
+ status: hash["status"],
25
+ merchant_lock: hash["merchant_lock"],
26
+ category_lock: hash["category_lock"],
27
+ keyword_lock: hash["keyword_lock"],
28
+ allowed_merchants: hash["allowed_merchants"],
29
+ allowed_categories: hash["allowed_categories"],
30
+ purpose: hash["purpose"],
31
+ one_time_use: hash["one_time_use"],
32
+ pre_authorization_required: hash["pre_authorization_required"],
33
+ card_id: hash["card_id"],
34
+ user: hash["user"] ? User.from_hash(hash["user"]) : nil,
35
+ organization:,
36
+ disbursements: hash["disbursements"]&.map { |d| Transfer.from_hash(d, client:, organization:) },
37
+ _client: client
38
+ )
39
+ end
40
+
41
+ # Adds funds to this grant.
42
+ # @param amount_cents [Integer]
43
+ # @return [CardGrant]
44
+ def topup!(amount_cents:)
45
+ require_client!
46
+ _client.topup_card_grant(id, amount_cents:)
47
+ end
48
+
49
+ # Withdraws funds back to the organization.
50
+ # @param amount_cents [Integer]
51
+ # @return [CardGrant]
52
+ def withdraw!(amount_cents:)
53
+ require_client!
54
+ _client.withdraw_card_grant(id, amount_cents:)
55
+ end
56
+
57
+ # Cancels this grant, returning remaining funds.
58
+ # @return [CardGrant]
59
+ def cancel!
60
+ require_client!
61
+ _client.cancel_card_grant(id)
62
+ end
63
+
64
+ # Activates a pending grant.
65
+ # @return [CardGrant]
66
+ def activate!
67
+ require_client!
68
+ _client.activate_card_grant(id)
69
+ end
70
+
71
+ # Refreshes grant data from the API.
72
+ # @return [CardGrant]
73
+ def reload!
74
+ require_client!
75
+ _client.card_grant(id)
76
+ end
77
+
78
+ # Updates grant attributes.
79
+ # @return [CardGrant]
80
+ def update!(**attrs)
81
+ require_client!
82
+ _client.update_card_grant(id, **attrs)
83
+ end
84
+
85
+ # @return [Boolean]
86
+ def merchant_lock? = !!merchant_lock
87
+
88
+ # @return [Boolean]
89
+ def category_lock? = !!category_lock
90
+
91
+ # @return [Boolean]
92
+ def keyword_lock? = !!keyword_lock
93
+
94
+ # @return [Boolean]
95
+ def one_time_use? = !!one_time_use
96
+
97
+ # @return [Boolean]
98
+ def pre_authorization_required? = !!pre_authorization_required
99
+ end
100
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HCBV4
4
+ # Mailed check payment details.
5
+ class Check < BaseTransactionDetail
6
+ attr_reader :address_city, :address_line1, :address_line2, :address_state, :address_zip,
7
+ :recipient_email, :check_number, :recipient_name, :payment_for, :sender
8
+
9
+ def initialize(id:, amount_cents: nil, memo: nil, status: nil, address_city: nil, address_line1: nil,
10
+ address_line2: nil, address_state: nil, address_zip: nil, recipient_email: nil,
11
+ check_number: nil, recipient_name: nil, payment_for: nil, sender: nil)
12
+ super(id:, amount_cents:, memo:, status:)
13
+ @address_city = address_city
14
+ @address_line1 = address_line1
15
+ @address_line2 = address_line2
16
+ @address_state = address_state
17
+ @address_zip = address_zip
18
+ @recipient_email = recipient_email
19
+ @check_number = check_number
20
+ @recipient_name = recipient_name
21
+ @payment_for = payment_for
22
+ @sender = sender
23
+ end
24
+
25
+ # @param hash [Hash] API response
26
+ # @return [Check]
27
+ def self.from_hash(hash)
28
+ new(
29
+ id: hash["id"],
30
+ amount_cents: hash["amount_cents"],
31
+ memo: hash["memo"],
32
+ status: hash["status"],
33
+ address_city: hash["address_city"],
34
+ address_line1: hash["address_line1"],
35
+ address_line2: hash["address_line2"],
36
+ address_state: hash["address_state"],
37
+ address_zip: hash["address_zip"],
38
+ recipient_email: hash["recipient_email"],
39
+ check_number: hash["check_number"],
40
+ recipient_name: hash["recipient_name"],
41
+ payment_for: hash["payment_for"],
42
+ sender: hash["sender"] ? User.from_hash(hash["sender"]) : nil
43
+ )
44
+ end
45
+ end
46
+
47
+ # Deposited check details.
48
+ class CheckDeposit < BaseTransactionDetail
49
+ attr_reader :front_url, :back_url, :submitter
50
+
51
+ def initialize(id:, amount_cents: nil, memo: nil, status: nil, front_url: nil, back_url: nil, submitter: nil)
52
+ super(id:, amount_cents:, memo:, status:)
53
+ @front_url = front_url
54
+ @back_url = back_url
55
+ @submitter = submitter
56
+ end
57
+
58
+ # @param hash [Hash] API response
59
+ # @return [CheckDeposit]
60
+ def self.from_hash(hash)
61
+ new(
62
+ id: hash["id"],
63
+ amount_cents: hash["amount_cents"],
64
+ memo: hash["memo"],
65
+ status: hash["status"],
66
+ front_url: hash["front_url"],
67
+ back_url: hash["back_url"],
68
+ submitter: hash["submitter"] ? User.from_hash(hash["submitter"]) : nil
69
+ )
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HCBV4
4
+ # A comment on a transaction.
5
+ Comment = Data.define(:id, :created_at, :content, :file, :admin_only, :user) do
6
+ # @param hash [Hash] API response
7
+ # @return [Comment]
8
+ def self.from_hash(hash)
9
+ new(
10
+ id: hash["id"], created_at: hash["created_at"], content: hash["content"],
11
+ file: hash["file"], admin_only: hash["admin_only"],
12
+ user: hash["user"] ? User.from_hash(hash["user"]) : nil
13
+ )
14
+ end
15
+
16
+ # @return [Boolean] true if only visible to HCB emails
17
+ def admin_only? = !!admin_only
18
+ end
19
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HCBV4
4
+ # A created donation record. Only contains the id.
5
+ # Full donation details are available via DonationTransaction on transactions.
6
+ Donation = Data.define(:id) do
7
+ # @param hash [Hash] API response
8
+ # @return [Donation]
9
+ def self.from_hash(hash) = new(id: hash["id"])
10
+ end
11
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HCBV4
4
+ # Donor info for a donation.
5
+ DonationDonor = Data.define(:name, :email, :recurring_donor_id) do
6
+ def self.from_hash(hash)
7
+ return nil unless hash
8
+
9
+ new(
10
+ name: hash["name"],
11
+ email: hash["email"],
12
+ recurring_donor_id: hash["recurring_donor_id"]
13
+ )
14
+ end
15
+ end
16
+
17
+ # UTM attribution info for tracking donation sources.
18
+ DonationAttribution = Data.define(:referrer, :utm_source, :utm_medium, :utm_campaign, :utm_term, :utm_content) do
19
+ def self.from_hash(hash)
20
+ return nil unless hash
21
+
22
+ new(
23
+ referrer: hash["referrer"],
24
+ utm_source: hash["utm_source"],
25
+ utm_medium: hash["utm_medium"],
26
+ utm_campaign: hash["utm_campaign"],
27
+ utm_term: hash["utm_term"],
28
+ utm_content: hash["utm_content"]
29
+ )
30
+ end
31
+ end
32
+
33
+ # Donation details on a transaction.
34
+ # @attr_reader recurring [Boolean, nil] true if recurring donation
35
+ # @attr_reader donor [DonationDonor, nil] donor info
36
+ # @attr_reader attribution [DonationAttribution, nil] UTM tracking
37
+ # @attr_reader message [String, nil] donor message
38
+ # @attr_reader donated_at [String, nil] ISO timestamp
39
+ # @attr_reader refunded [Boolean, nil]
40
+ class DonationTransaction < BaseTransactionDetail
41
+ attr_reader :recurring, :donor, :attribution, :message, :donated_at, :refunded
42
+
43
+ def initialize(id: nil, amount_cents: nil, memo: nil, status: nil, recurring: nil, donor: nil,
44
+ attribution: nil, message: nil, donated_at: nil, refunded: nil)
45
+ super(id:, amount_cents:, memo:, status:)
46
+ @recurring = recurring
47
+ @donor = donor
48
+ @attribution = attribution
49
+ @message = message
50
+ @donated_at = donated_at
51
+ @refunded = refunded
52
+ end
53
+
54
+ # @param hash [Hash] API response
55
+ # @return [DonationTransaction]
56
+ def self.from_hash(hash)
57
+ new(
58
+ id: hash["id"],
59
+ amount_cents: hash["amount_cents"],
60
+ memo: hash["memo"],
61
+ status: hash["status"],
62
+ recurring: hash["recurring"],
63
+ donor: DonationDonor.from_hash(hash["donor"]),
64
+ attribution: DonationAttribution.from_hash(hash["attribution"]),
65
+ message: hash["message"],
66
+ donated_at: hash["donated_at"],
67
+ refunded: hash["refunded"]
68
+ )
69
+ end
70
+
71
+ # @return [Boolean]
72
+ def recurring? = !!recurring
73
+
74
+ # @return [Boolean]
75
+ def refunded? = !!refunded
76
+ end
77
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HCBV4
4
+ # Expense reimbursement payout details.
5
+ class ExpensePayout < BaseTransactionDetail
6
+ attr_reader :report_id
7
+
8
+ def initialize(id: nil, amount_cents: nil, memo: nil, status: nil, report_id: nil)
9
+ super(id:, amount_cents:, memo:, status:)
10
+ @report_id = report_id
11
+ end
12
+
13
+ # @param hash [Hash] API response
14
+ # @return [ExpensePayout]
15
+ def self.from_hash(hash)
16
+ new(
17
+ id: hash["id"],
18
+ amount_cents: hash["amount_cents"],
19
+ memo: hash["memo"],
20
+ status: hash["status"],
21
+ report_id: hash["report_id"]
22
+ )
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HCBV4
4
+ # An invitation to join an organization.
5
+ Invitation = Data.define(:id, :created_at, :accepted, :role, :sender, :organization, :_client) do
6
+ include Resource
7
+
8
+ # @param hash [Hash] API response
9
+ # @param client [Client, nil]
10
+ # @return [Invitation]
11
+ def self.from_hash(hash, client: nil)
12
+ new(
13
+ id: hash["id"],
14
+ created_at: hash["created_at"],
15
+ accepted: hash["accepted"],
16
+ role: hash["role"],
17
+ sender: hash["sender"] ? User.from_hash(hash["sender"]) : nil,
18
+ organization: hash["organization"] ? Organization.from_hash(hash["organization"]) : nil,
19
+ _client: client
20
+ )
21
+ end
22
+
23
+ # Accepts this invitation.
24
+ # @return [Invitation]
25
+ def accept!
26
+ require_client!
27
+ _client.accept_invitation(id)
28
+ end
29
+
30
+ # Rejects this invitation.
31
+ # @return [Invitation]
32
+ def reject!
33
+ require_client!
34
+ _client.reject_invitation(id)
35
+ end
36
+
37
+ # Refreshes invitation data from the API.
38
+ # @return [Invitation]
39
+ def reload!
40
+ require_client!
41
+ _client.invitation(id)
42
+ end
43
+
44
+ # @return [Boolean]
45
+ def accepted? = !!accepted
46
+ end
47
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HCBV4
4
+ # An invoice sent to a sponsor.
5
+ Invoice = Data.define(
6
+ :id, :status, :created_at, :to, :amount_due, :memo, :due_date,
7
+ :item_amount, :item_description, :sponsor_id, :_client
8
+ ) do
9
+ include Resource
10
+
11
+ # @param hash [Hash] API response
12
+ # @param client [Client, nil]
13
+ # @return [Invoice]
14
+ def self.from_hash(hash, client: nil)
15
+ new(
16
+ id: hash["id"], status: hash["status"], created_at: hash["created_at"], to: hash["to"],
17
+ amount_due: hash["amount_due"], memo: hash["memo"], due_date: hash["due_date"],
18
+ item_amount: hash["item_amount"], item_description: hash["item_description"], sponsor_id: hash["sponsor_id"],
19
+ _client: client
20
+ )
21
+ end
22
+
23
+ # Refreshes invoice data from the API.
24
+ # @return [Invoice]
25
+ def reload!
26
+ require_client!
27
+ _client.invoice(id)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HCBV4
4
+ # Sponsor info embedded in invoice transactions.
5
+ InvoiceSponsor = Data.define(:id, :name, :email) do
6
+ def self.from_hash(hash)
7
+ return nil unless hash
8
+
9
+ new(
10
+ id: hash["id"],
11
+ name: hash["name"],
12
+ email: hash["email"]
13
+ )
14
+ end
15
+ end
16
+
17
+ # Invoice payment details on a transaction.
18
+ class InvoiceTransaction < BaseTransactionDetail
19
+ attr_reader :sent_at, :paid_at, :description, :due_date, :sponsor
20
+
21
+ def initialize(id: nil, amount_cents: nil, memo: nil, status: nil, sent_at: nil, paid_at: nil,
22
+ description: nil, due_date: nil, sponsor: nil)
23
+ super(id:, amount_cents:, memo:, status:)
24
+ @sent_at = sent_at
25
+ @paid_at = paid_at
26
+ @description = description
27
+ @due_date = due_date
28
+ @sponsor = sponsor
29
+ end
30
+
31
+ # @param hash [Hash] API response
32
+ # @return [InvoiceTransaction]
33
+ def self.from_hash(hash)
34
+ new(
35
+ id: hash["id"],
36
+ amount_cents: hash["amount_cents"],
37
+ memo: hash["memo"],
38
+ status: hash["status"],
39
+ sent_at: hash["sent_at"],
40
+ paid_at: hash["paid_at"],
41
+ description: hash["description"],
42
+ due_date: hash["due_date"],
43
+ sponsor: InvoiceSponsor.from_hash(hash["sponsor"])
44
+ )
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HCBV4
4
+ # Merchant info for card transactions.
5
+ # @attr_reader name [String, nil] raw merchant name from Stripe
6
+ # @attr_reader smart_name [String, nil] cleaned up merchant name
7
+ # @attr_reader country [String, nil] two-letter country code
8
+ # @attr_reader network_id [String, nil] merchant category code
9
+ Merchant = Data.define(:name, :smart_name, :country, :network_id) do
10
+ # @param hash [Hash] API response
11
+ # @return [Merchant]
12
+ def self.from_hash(hash)
13
+ new(name: hash["name"], smart_name: hash["smart_name"], country: hash["country"], network_id: hash["network_id"])
14
+ end
15
+ end
16
+ end