Skip to content
Open
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
1 change: 1 addition & 0 deletions lib/secretariat/constants.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ module Secretariat
TAX_CALCULATION_METHODS = %i[HORIZONTAL VERTICAL NONE UNKNOWN].freeze

UNIT_CODES = {
:YEAR => "ANN",
:PIECE => "C62",
:DAY => "DAY",
:HECTARE => "HAR",
Expand Down
18 changes: 18 additions & 0 deletions lib/secretariat/line_item.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ module Secretariat
:charge_amount,
:origin_country_code,
:currency_code,
:service_period_start, # if start present start & end are required
:service_period_end, # end has to be on or after start (secretariat does not validate this)
keyword_init: true
) do

Expand Down Expand Up @@ -181,6 +183,22 @@ def to_xml(xml, line_item_index, version: 2, validate: true)
xml['ram'].send(percent,Helpers.format(tax_percent))
end
end

if version == 2 && self.service_period_start && self.service_period_end
xml['ram'].BillingSpecifiedPeriod do
xml['ram'].StartDateTime do
xml['udt'].DateTimeString(format: '102') do
xml.text(service_period_start.strftime("%Y%m%d"))
end
end
xml['ram'].EndDateTime do
xml['udt'].DateTimeString(format: '102') do
xml.text(service_period_end.strftime("%Y%m%d"))
end
end
end
end

monetary_summation = by_version(version, 'SpecifiedTradeSettlementMonetarySummation', 'SpecifiedTradeSettlementLineMonetarySummation')
xml['ram'].send(monetary_summation) do
Helpers.currency_element(xml, 'ram', 'LineTotalAmount', (quantity.negative? ? -charge_amount : charge_amount), currency_code, add_currency: version == 1)
Expand Down
80 changes: 80 additions & 0 deletions test/invoice_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,61 @@ def make_eu_invoice(tax_category: :REVERSECHARGE)
)
end

def make_eu_invoice_with_line_item_billing_period(tax_category: :REVERSECHARGE)
seller = TradeParty.new(
name: 'Depfu inc',
street1: 'Quickbornstr. 46',
city: 'Hamburg',
postal_code: '20253',
country_id: 'DE',
vat_id: 'DE304755032'
)
buyer = TradeParty.new(
name: 'Depfu inc',
street1: 'Quickbornstr. 46',
city: 'Hamburg',
postal_code: '20253',
country_id: 'SE',
vat_id: 'SE304755032'
)
line_item = LineItem.new(
name: 'Depfu Premium Plan',
quantity: 1,
gross_amount: BigDecimal('29'),
net_amount: BigDecimal('29'),
unit: :YEAR,
charge_amount: BigDecimal('29'),
tax_category: tax_category,
tax_percent: 0,
tax_amount: 0,
origin_country_code: 'DE',
currency_code: 'EUR',
service_period_start: Date.today,
service_period_end: Date.today + 364,
)
Invoice.new(
id: '12345',
issue_date: Date.today,
# service_period on line_item. removed here to simplify testing of BillingSpecifiedPeriod presence
# service_period_start: Date.today,
# service_period_end: Date.today + 30,
seller: seller,
buyer: buyer,
line_items: [line_item],
currency_code: 'USD',
payment_type: :CREDITCARD,
payment_text: 'Kreditkarte',
tax_category: tax_category,
tax_amount: 0,
basis_amount: BigDecimal('29'),
grand_total_amount: BigDecimal('29'),
due_amount: 0,
paid_amount: 29,
payment_due_date: Date.today + 14,
notes: "This is a test invoice",
)
end

def make_foreign_invoice(tax_category: :TAXEXEMPT)
seller = TradeParty.new(
name: 'Depfu inc',
Expand Down Expand Up @@ -381,6 +436,31 @@ def test_simple_eu_invoice_v2
puts e.errors
end

def test_simple_eu_invoice_v2_with_line_item_billing_period
begin
xml = make_eu_invoice_with_line_item_billing_period.to_xml(version: 2)
rescue ValidationError => e
pp e.errors
end

assert_match(/<ram:CategoryCode>AE<\/ram:CategoryCode>/, xml)
assert_match(/<ram:ExemptionReason>Reverse Charge<\/ram:ExemptionReason>/, xml)
assert_match(/<ram:RateApplicablePercent>/, xml)
assert_match(/<ram:BillingSpecifiedPeriod>/, xml)

v = Validator.new(xml, version: 2)
errors = v.validate_against_schema
if !errors.empty?
puts xml
errors.each do |error|
puts error
end
end
assert_equal [], errors
rescue ValidationError => e
puts e.errors
end

def test_simple_foreign_invoice_v2_taxexpempt
begin
xml = make_foreign_invoice(tax_category: :TAXEXEMPT).to_xml(version: 2)
Expand Down