Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
78a2154
setup Intacct service url to allow customize the intacct service url.…
bernespinoza Apr 11, 2023
c9af112
returns response validation in delete payment and invoice
bernespinoza Apr 11, 2023
8550cb5
Updates on_error hook
bernespinoza Apr 19, 2023
da3c49b
Raise errors on error when objects already exists
bernespinoza Apr 19, 2023
183be4c
fixes customer and bill queries because they are failing when retrivi…
bernespinoza Apr 25, 2023
a6d44c6
safety fail on empty response
bernespinoza Apr 25, 2023
765693e
updates intacct system id of vendors
bernespinoza Apr 26, 2023
d6439ea
use object intacct_system_id to get data and update it from intacct
bernespinoza Apr 26, 2023
138ac11
force ach account info numbers to be numbers instead of strings
bernespinoza Apr 27, 2023
5917dc9
customer_fields
bernespinoza Nov 16, 2023
43a1258
fixes for empty values
bernespinoza Nov 24, 2023
6faac5e
remove new files
bernespinoza Nov 24, 2023
9797757
remove intacct_api and response
bernespinoza Nov 24, 2023
372566b
rename traverse to each
bernespinoza Dec 11, 2025
489c6c9
load customer data
bernespinoza Dec 20, 2025
0d05149
create a new invoice object
bernespinoza Dec 20, 2025
d1ecfab
v0.0.3: controlid, timeouts, logger, customer_fields, error nil guard
bernespinoza Mar 14, 2026
919f4cf
Update gemfile and token
bernespinoza Apr 18, 2026
3c682ea
add intacct_object_id support for objects
bernespinoza Apr 18, 2026
0838807
Add vendor content_xml custom_vendor_fields and update the required f…
bernespinoza Apr 18, 2026
d3e8843
add support for default fields and object_id to customer
bernespinoza Apr 18, 2026
b73814a
Intacct::Customer define hooks to required fields and get fields
bernespinoza Apr 18, 2026
4d373eb
update vendor and customer readme
bernespinoza Apr 18, 2026
0586bdc
fix vendor contact info
bernespinoza Apr 18, 2026
3514ab0
validate ach routing fields
bernespinoza Apr 18, 2026
1cb0bfe
add invoice and bill tests for prefix
bernespinoza Apr 18, 2026
a86c4a5
update hooks
bernespinoza Apr 18, 2026
574484a
update invoice and bill create methods
bernespinoza Apr 18, 2026
1b8191d
udpdate invoice and bill to define default fields
bernespinoza Apr 18, 2026
8283659
fix return and raise error
bernespinoza Apr 18, 2026
59ad041
fix issues catching times, intacct key and system id introducing doma…
bernespinoza Apr 18, 2026
26f5914
update intacct errors code
bernespinoza Apr 18, 2026
fc66ed6
fix the domain object
bernespinoza Apr 18, 2026
c770a36
allow create a vendor with uncomplete data
bernespinoza Apr 18, 2026
dd38013
add more support for errors
bernespinoza Apr 18, 2026
73d498c
apply vendor address2 vendorid customerid validations
bernespinoza Apr 18, 2026
d3ca0d9
read the vendor and customer ids
bernespinoza Apr 18, 2026
b630012
update vendor content_xml order
bernespinoza Apr 19, 2026
c491516
remove conversion to integers in ach account numbers
bernespinoza Apr 19, 2026
9b2d71d
get list return intacct status and responses
bernespinoza Apr 20, 2026
f1b3b9e
add intacct_label to label actions
bernespinoza Apr 20, 2026
adcfe98
remove validations for ach_account
bernespinoza Apr 20, 2026
e8ec5af
set address2 after address1 when exists
bernespinoza Apr 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ source 'https://rubygems.org'
# Specify your gem's dependencies in intacct.gemspec
gemspec

gem "rails", "~> 4.0.0"
gem 'turnip', github: 'cj/turnip'
gem 'turnip', '>= 3.0'
309 changes: 309 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,315 @@ Or install it yourself as:

TODO: Write usage instructions here

## Object Interface Requirements

Each domain class wraps a plain Ruby object. The gem calls methods on that object via `respond_to?` — implement only what you need.

---

### `Intacct::Vendor.new(vendor_object)`

| Method | Required? | Notes |
|---|---|---|
| `id` | Required | Used in vendorid: `vendor_prefix + id` |
| `name` | Required | Vendor display name |
| `intacct_system_id` | Required | `nil` for new; Intacct ID string after create. Must persist. |
| `intacct_system_id=` | Required | Written after create; cleared after delete |
| `contactname` | Required | e.g. `"#{last_name}, #{first_name} (#{id})"` |
| `full_name` | Required | Used in `printas` |
| `first_name` | Required | |
| `last_name` | Required | |
| `email` | Required | |
| `tax_number` | Optional | |
| `company_name` | Optional | |
| `business_phone` | Optional | |
| `cell_phone` | Optional | |
| `billing_address` | Optional | Must respond to `address1`, `address2`, `city`, `state`, `zipcode` |
| `ach_routing_number` | Optional | If present, ACH block is included |
| `ach_account_number` | Conditional | Required if `ach_routing_number` present |
| `ach_account_type` | Conditional | Intacct-formatted string, e.g. `"Savings Account"`, `"Checking Account"` |
| `ach_remittance_type` | Conditional | Intacct-formatted string, e.g. `"CCD"` or `"PPD"` — client derives from domain logic |
| `intacct_object_id` | Optional | Override vendorid (default: `vendor_prefix + id`) |
| `intacct_key` | Optional | Recommended — gem writes back via `respond_to?` |
| `intacct_key=` | Optional | Recommended |

**Required-fields validation** is configured in `Intacct.setup`, not on the domain object:

```ruby
Intacct.setup do |config|
# Gem default — used when neither of the below is set (default: [:id, :name])
config.intacct_vendor_required_fields = [:id, :name]

# If only create is set, it applies to both create and update.
# If both are set, each applies to its respective operation.
# If only update is set, create falls back to intacct_vendor_required_fields.
config.intacct_vendor_create_required_fields = [:id, :name, :email]
config.intacct_vendor_update_required_fields = [:id, :name]
end
```

Resolution order:
- **create** → `intacct_vendor_create_required_fields` || `intacct_vendor_required_fields`
- **update** → `intacct_vendor_update_required_fields` || `intacct_vendor_create_required_fields` || `intacct_vendor_required_fields`

**Hooks:**

```ruby
vendor = Intacct::Vendor.new(my_vendor)

# Instance-level (one vendor)
vendor.custom_vendor_fields do |xml, intacct|
xml.some_custom_field "value"
end

# Class-level in an initializer (all vendors)
Intacct::Vendor.custom_vendor_fields do |xml, intacct|
xml.some_custom_field "value"
end

# Replace the entire body with a custom block
vendor.content_xml do |xml|
xml.name "Custom Name"
xml.vendtype "Custom Type"
xml.contactinfo { xml.contact { xml.contactname "Custom Contact" } }
end

vendor.create
```

**Inspect the default field hash:**

```ruby
vendor.content_xml
# => { name: "Acme Corp", vendtype: "Appraiser", ..., contactinfo: { ... } }
```

---

### `Intacct::Invoice.new(invoice: obj, vendor: obj, customer: obj)`

**`invoice_obj`:**

| Method | Required? | Notes |
|---|---|---|
| `id` | Required | |
| `created_at` | Required | Must respond to `strftime` |
| `intacct_system_id` | Required | |
| `intacct_system_id=` | Required | |
| `intacct_key` / `intacct_key=` | Recommended | |
| `intacct_object_id` | Optional | Override invoiceno |

`customer_obj` and `vendor_obj` follow the same interfaces as their standalone `new` calls above.

**Required-fields validation** is configured in `Intacct.setup`. Fields are checked on `invoice_obj` before the create call:

The gem always checks that `invoice_obj` provides either `intacct_object_id` or `id` (used to build the invoiceno). Additional fields are configurable:

```ruby
Intacct.setup do |config|
# Gem default — [:created_at] (consumed by content_xml; id/intacct_object_id checked separately)
config.intacct_invoice_required_fields = [:created_at]

# If only create is set, it applies to both create and update.
# If both are set, each applies to its respective operation.
# If only update is set, create falls back to intacct_invoice_required_fields.
config.intacct_invoice_create_required_fields = [:created_at]
config.intacct_invoice_update_required_fields = [:created_at]
end
```

Resolution order:
- **create** → `intacct_invoice_create_required_fields` || `intacct_invoice_required_fields`
- **update** → `intacct_invoice_update_required_fields` || `intacct_invoice_create_required_fields` || `intacct_invoice_required_fields`

**`content_xml`:**

```ruby
invoice = Intacct::Invoice.new(composite)
invoice.customer_data = OpenStruct.new(termname: "Net 30") # set before calling content_xml

# Inspect the default field hash (call after customer/vendor are provisioned,
# or just let create do it automatically):
invoice.content_xml
# => { customerid: "C123", datecreated: { year: "2024", ... }, termname: "Net 30", invoiceno: "INV-456" }

# Replace the entire body with a custom block:
invoice.content_xml do |xml|
xml.customerid object.customer.intacct_system_id
xml.invoiceno "CUSTOM-001"
end
```

**Hooks:**

```ruby
# Instance-level (one invoice)
invoice = Intacct::Invoice.new(invoice: my_invoice, vendor: my_vendor, customer: my_customer)
invoice.custom_invoice_fields do |xml, intacct|
xml.some_custom_field "value"
end

# Class-level in an initializer (all invoices)
Intacct::Invoice.custom_invoice_fields do |xml, intacct|
xml.some_custom_field "value"
end
```

---

### `Intacct::Bill.new(bill: obj, vendor: obj, customer: obj)`

Same composite pattern as Invoice — `bill_obj` follows the same shape as `invoice_obj`.

**Required-fields validation** is configured in `Intacct.setup`. Fields are checked on `payment_obj` before the create call:

The gem always checks that `payment_obj` provides either `intacct_object_id` or `id` (used to build the bill number). Additional fields are configurable:

```ruby
Intacct.setup do |config|
# Gem default — [:created_at, :paid_at] (consumed by content_xml; id/intacct_object_id checked separately)
config.intacct_bill_required_fields = [:created_at, :paid_at]

# If only create is set, it applies to both create and update.
# If both are set, each applies to its respective operation.
# If only update is set, create falls back to intacct_bill_required_fields.
config.intacct_bill_create_required_fields = [:created_at, :paid_at]
config.intacct_bill_update_required_fields = [:created_at, :paid_at]
end
```

Resolution order:
- **create** → `intacct_bill_create_required_fields` || `intacct_bill_required_fields`
- **update** → `intacct_bill_update_required_fields` || `intacct_bill_create_required_fields` || `intacct_bill_required_fields`

**`content_xml`:**

```ruby
bill = Intacct::Bill.new(composite)

# Inspect the default field hash (call after vendor is provisioned,
# or just let create do it automatically):
bill.content_xml
# => { vendorid: "V123", datecreated: { year: "2024", ... }, dateposted: { ... }, datedue: { ... } }

# Replace the entire body with a custom block:
bill.content_xml do |xml|
xml.vendorid object.vendor.intacct_system_id
end
```

**Hooks:**

```ruby
# Instance-level (one bill)
bill = Intacct::Bill.new(payment: my_bill, vendor: my_vendor, customer: my_customer)
bill.custom_bill_fields do |xml, intacct|
xml.some_custom_field "value"
end
bill.bill_item_fields do |xml, intacct|
xml.billitems { xml.lineitem { xml.amount "100.00" } }
end

# Class-level in an initializer (all bills)
Intacct::Bill.custom_bill_fields do |xml, intacct|
xml.some_custom_field "value"
end
Intacct::Bill.bill_item_fields do |xml, intacct|
xml.billitems { xml.lineitem { xml.amount "100.00" } }
end
```

---

### `Intacct::Customer.new(customer_object)`

| Method | Required? | Notes |
|---|---|---|
| `id` | Required | Used in customerid: `customer_prefix + id` |
| `name` | Required | Customer display name |
| `intacct_system_id` | Required | `nil` for new; Intacct ID string after create. Must persist. |
| `intacct_system_id=` | Required | Written after create; cleared after delete |
| `intacct_object_id` | Optional | Override customerid (default: `customer_prefix + id`) |
| `intacct_key` | Optional | Recommended — gem writes back via `respond_to?` |
| `intacct_key=` | Optional | Recommended |

**Required-fields validation** follows the same setup pattern as Vendor:

```ruby
Intacct.setup do |config|
config.intacct_customer_required_fields = [:id, :name] # gem default
config.intacct_customer_create_required_fields = [:id, :name]
config.intacct_customer_update_required_fields = [:id, :name]
end
```

Resolution order:
- **create** → `intacct_customer_create_required_fields` || `intacct_customer_required_fields`
- **update** → `intacct_customer_update_required_fields` || `intacct_customer_create_required_fields` || `intacct_customer_required_fields`

**`get` fields** — controls which fields are fetched from Intacct when calling `customer.get`. Defaults to a standard set; override in setup to fetch only what you need:

```ruby
Intacct.setup do |config|
config.customer_fields = [
:customerid,
:name,
:termname,
:auto_employee,
:auto_commission_start_date,
:auto_commission_end_date,
:auto_commission_rate,
:property_employee,
:property_commission_start_date,
:property_commission_end_date,
:property_commission_rate,
:subro_employee,
:subro_commission_start_date,
:subro_commission_end_date,
:subro_commission_rate
]
end
```

You can also pass fields directly to `get` to override the setup value for a single call:

```ruby
Intacct::Customer.new(my_customer).get(:customerid, :name, :termname)
```

**Hooks:**

```ruby
customer = Intacct::Customer.new(my_customer)

# Instance-level (one customer)
customer.custom_customer_fields do |xml, intacct|
xml.some_custom_field "value"
end

# Class-level in an initializer (all customers)
Intacct::Customer.custom_customer_fields do |xml, intacct|
xml.some_custom_field "value"
end

# Replace the entire body with a custom block
customer.content_xml do |xml|
xml.name "Custom Name"
xml.status "active"
end

customer.create
```

**Inspect the default field hash:**

```ruby
customer.content_xml
# => { name: "Acme Corp", comments: nil, status: "active" }
```

---

## Contributing

1. Fork it
Expand Down
7 changes: 4 additions & 3 deletions intacct.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ require 'intacct/version'
Gem::Specification.new do |spec|
spec.name = "intacct"
spec.version = Intacct::VERSION
spec.authors = ["CJ Lazell"]
spec.email = ["cjlazell@gmail.com"]
spec.authors = ['CJ Lazell', 'Bernardo Espinoza']
spec.email = ["cjlazell@gmail.com", 'bernardo466@gmail.com']
spec.description = %q{Ruby lib to communicate with the Intacct API system.}
spec.summary = %q{Ruby Intacct API Client}
spec.homepage = ""
Expand All @@ -20,7 +20,8 @@ Gem::Specification.new do |spec|

spec.add_dependency "nokogiri"
spec.add_dependency "hooks"
spec.add_development_dependency "bundler", "~> 1.3"
spec.add_dependency "activesupport", ">= 6.0"
spec.add_development_dependency "bundler", "~> 2.4"
spec.add_development_dependency "rake"
spec.add_development_dependency "rspec"
spec.add_development_dependency "turnip"
Expand Down
Loading