Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat netsuite taxes payloads #2622

Merged
merged 2 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions app/services/integrations/aggregator/base_payload.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ def collection_mapping(type)
private

attr_reader :integration

def tax_item_complete?
tax_item&.tax_nexus.present? && tax_item&.tax_type.present? && tax_item&.tax_code.present?
end
end
end
end
115 changes: 101 additions & 14 deletions app/services/integrations/aggregator/credit_notes/payloads/netsuite.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,66 @@ module CreditNotes
module Payloads
class Netsuite < BasePayload
def body
{
result = {
'type' => 'creditmemo',
'isDynamic' => true,
'columns' => {
'tranid' => credit_note.number,
'entity' => integration_customer.external_customer_id,
'istaxable' => true,
'taxitem' => tax_item.external_id,
'taxamountoverride' => amount(credit_note.taxes_amount_cents, resource: credit_note),
'otherrefnum' => credit_note.number,
'custbody_lago_id' => credit_note.id,
'tranId' => credit_note.id
},
'columns' => columns,
'lines' => [
{
'sublistId' => 'item',
'lineItems' => credit_note.items.map { |credit_note_item| item(credit_note_item) } + coupons
'lineItems' => credit_note_items + coupons
}
],
'options' => {
'ignoreMandatoryFields' => false
}
}

if tax_item_complete?
result['taxdetails'] = [
{
'sublistId' => 'taxdetails',
'lineItems' => tax_line_items_with_adjusted_taxes + coupon_taxes
}
]
end

result
end

private

def credit_note_items
items.map { |credit_note_item| item(credit_note_item) }
end

def tax_line_items
items.map { |credit_note_item| tax_line_item(credit_note_item) }
end

def items
@items ||= credit_note.items.order(created_at: :asc)
end

def columns
result = {
'tranid' => credit_note.number,
'entity' => integration_customer.external_customer_id,
'taxregoverride' => true,
'taxdetailsoverride' => true,
'otherrefnum' => credit_note.number,
'custbody_ava_disable_tax_calculation' => true,
'custbody_lago_id' => credit_note.id,
'tranId' => credit_note.id
}

if tax_item&.tax_nexus.present?
result['nexus'] = tax_item.tax_nexus
end

result
end

def item(credit_note_item)
fee = credit_note_item.fee

Expand All @@ -56,10 +89,46 @@ def item(credit_note_item)
'item' => mapped_item.external_id,
'account' => mapped_item.external_account_code,
'quantity' => 1,
'rate' => amount(credit_note_item.amount_cents, resource: credit_note_item.credit_note)
'rate' => amount(credit_note_item.amount_cents, resource: credit_note_item.credit_note),
'taxdetailsreference' => credit_note_item.id
}
end

def tax_line_item(credit_note_item)
{
'taxdetailsreference' => credit_note_item.id,
'taxamount' => amount(taxes_amount(credit_note_item), resource: credit_note_item.credit_note),
'taxbasis' => 1,
'taxrate' => credit_note_item.fee.taxes_rate,
'taxtype' => tax_item.tax_type,
'taxcode' => tax_item.tax_code
}
end

def tax_line_items_with_adjusted_taxes
taxes_amount_cents_sum = tax_line_items.sum { |f| f['taxamount'].to_d }

return tax_line_items if taxes_amount_cents_sum == credit_note.taxes_amount_cents

adjusted_first_tax = false

tax_line_items.map do |credit_note_item|
if credit_note_item['taxamount'] > 0 && !adjusted_first_tax
amount = amount(credit_note.taxes_amount_cents, resource: credit_note)
credit_note_item['taxamount'] += amount - taxes_amount_cents_sum
adjusted_first_tax = true
end

credit_note_item
end
end

def taxes_amount(credit_note_item)
subunit_to_unit = credit_note_item.amount.currency.subunit_to_unit.to_d
amount = credit_note_item.amount_cents.fdiv(subunit_to_unit) * credit_note_item.credit_note.taxes_rate
amount.round(2)
end

def coupons
output = []

Expand All @@ -68,7 +137,25 @@ def coupons
'item' => coupon_item&.external_id,
'account' => coupon_item&.external_account_code,
'quantity' => 1,
'rate' => -amount(credit_note.coupons_adjustment_amount_cents, resource: credit_note)
'rate' => -amount(credit_note.coupons_adjustment_amount_cents, resource: credit_note),
'taxdetailsreference' => 'coupon_item'
}
end

output
end

def coupon_taxes
output = []

if credit_note.coupons_adjustment_amount_cents > 0
output << {
'taxbasis' => 1,
'taxamount' => 0,
'taxrate' => credit_note.taxes_rate,
'taxtype' => tax_item.tax_type,
'taxcode' => tax_item.tax_code,
'taxdetailsreference' => 'coupon_item'
}
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module Invoices
module Payloads
class Anrok < BasePayload
def initialize(integration_customer:, invoice:)
super(integration_customer:, invoice:)
super
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def body
'number' => invoice.number,
'currency' => invoice.currency,
'type' => 'ACCREC',
'fees' => (tax_adjusted_fees + discounts)
'fees' => (tax_adjusted_fee_items + discounts)
}
]
end
Expand All @@ -34,14 +34,18 @@ def body
attr_accessor :remaining_taxes_amount_cents

def fees
@fees ||= invoice.fees.order(created_at: :asc).map { |fee| item(fee) }
@fees ||= invoice.fees.order(created_at: :asc)
end

def tax_adjusted_fees
remaining_taxes_amount_cents = invoice.taxes_amount_cents - fees.sum { |f| f['taxes_amount_cents'] }.round
def fee_items
fees.map { |fee| item(fee) }
end

def tax_adjusted_fee_items
remaining_taxes_amount_cents = invoice.taxes_amount_cents - fee_items.sum { |f| f['taxes_amount_cents'] }.round

fees.map do |fee|
# TODO: if no coupon fix the tax rounding issue here:
fee_items.map do |fee|
# If no coupon fix the tax rounding issue here
if remaining_taxes_amount_cents.to_i.abs > 0 &&
invoice.coupons_amount_cents == 0 &&
fee['taxes_amount_cents'] > remaining_taxes_amount_cents.to_i.abs
Expand Down
95 changes: 83 additions & 12 deletions app/services/integrations/aggregator/invoices/payloads/netsuite.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,31 @@ class Netsuite < BasePayload
MAX_DECIMALS = 15

def body
{
result = {
'type' => type,
'isDynamic' => true,
'columns' => columns,
'lines' => [
{
'sublistId' => 'item',
'lineItems' => invoice.fees.where('amount_cents > ?', 0).order(created_at: :asc).map do |fee|
item(fee)
end + discounts
'lineItems' => fee_items + discounts
}
],
'options' => {
'ignoreMandatoryFields' => false
}
}

if tax_item_complete?
result['taxdetails'] = [
{
'sublistId' => 'taxdetails',
'lineItems' => tax_line_items + discount_taxes
}
]
end

result
end

private
Expand All @@ -32,22 +41,39 @@ def columns
result = {
'tranid' => invoice.id,
'entity' => integration_customer.external_customer_id,
'istaxable' => true,
'otherrefnum' => invoice.number,
'custbody_lago_id' => invoice.id,
'custbody_ava_disable_tax_calculation' => true,
'custbody_lago_invoice_link' => invoice_url,
'duedate' => due_date
}

if tax_item
result['taxitem'] = tax_item.external_id
result['taxamountoverride'] = amount(invoice.taxes_amount_cents, resource: invoice)
if tax_item&.tax_nexus.present?
result['nexus'] = tax_item.tax_nexus
end

result
end

def tax_line_items
fees.map { |fee| tax_line_item(fee) }
end

def tax_line_item(fee)
{
'taxdetailsreference' => fee.id,
'taxamount' => amount(fee.taxes_amount_cents, resource: invoice),
'taxbasis' => 1,
'taxrate' => fee.taxes_rate,
'taxtype' => tax_item.tax_type,
'taxcode' => tax_item.tax_code
}
end

def fees
@fees ||= invoice.fees.where('amount_cents > ?', 0).order(created_at: :asc)
end

def invoice_url
url = ENV["LAGO_FRONT_URL"].presence || "https://app.getlago.com"

Expand Down Expand Up @@ -79,7 +105,8 @@ def item(fee)
'item' => mapped_item.external_id,
'account' => mapped_item.external_account_code,
'quantity' => fee.units,
'rate' => limited_rate(fee.precise_unit_amount)
'rate' => limited_rate(fee.precise_unit_amount),
'taxdetailsreference' => fee.id
}
end

Expand All @@ -91,7 +118,8 @@ def discounts
'item' => coupon_item.external_id,
'account' => coupon_item.external_account_code,
'quantity' => 1,
'rate' => -amount(invoice.coupons_amount_cents, resource: invoice)
'rate' => -amount(invoice.coupons_amount_cents, resource: invoice),
'taxdetailsreference' => 'coupon_item'
}
end

Expand All @@ -100,7 +128,8 @@ def discounts
'item' => credit_item.external_id,
'account' => credit_item.external_account_code,
'quantity' => 1,
'rate' => -amount(invoice.prepaid_credit_amount_cents, resource: invoice)
'rate' => -amount(invoice.prepaid_credit_amount_cents, resource: invoice),
'taxdetailsreference' => 'credit_item'
}
end

Expand All @@ -109,7 +138,49 @@ def discounts
'item' => credit_note_item.external_id,
'account' => credit_note_item.external_account_code,
'quantity' => 1,
'rate' => -amount(invoice.credit_notes_amount_cents, resource: invoice)
'rate' => -amount(invoice.credit_notes_amount_cents, resource: invoice),
'taxdetailsreference' => 'credit_note_item'
}
end

output
end

def discount_taxes
output = []

if invoice.coupons_amount_cents > 0
tax_diff_amount_cents = invoice.taxes_amount_cents - fees.sum { |f| f['taxes_amount_cents'] }

output << {
'taxbasis' => 1,
'taxamount' => amount(tax_diff_amount_cents, resource: invoice),
'taxrate' => invoice.taxes_rate,
'taxtype' => tax_item.tax_type,
'taxcode' => tax_item.tax_code,
'taxdetailsreference' => 'coupon_item'
}
end

if credit_item && invoice.prepaid_credit_amount_cents > 0
output << {
'taxbasis' => 1,
'taxamount' => 0,
'taxrate' => invoice.taxes_rate,
'taxtype' => tax_item.tax_type,
'taxcode' => tax_item.tax_code,
'taxdetailsreference' => 'credit_item'
}
end

if credit_note_item && invoice.credit_notes_amount_cents > 0
output << {
'taxbasis' => 1,
'taxamount' => 0,
'taxrate' => invoice.taxes_rate,
'taxtype' => tax_item.tax_type,
'taxcode' => tax_item.tax_code,
'taxdetailsreference' => 'credit_note_item'
}
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module Invoices
module Payloads
class Xero < BasePayload
def initialize(integration_customer:, invoice:)
super(integration_customer:, invoice:)
super
end
end
end
Expand Down
Loading