xrechnung 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.
- checksums.yaml +7 -0
- data/.github/workflows/validate-fixtures.yml +32 -0
- data/.gitignore +19 -0
- data/.rspec +3 -0
- data/.rubocop.yml +375 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +70 -0
- data/LICENSE.txt +21 -0
- data/README.md +44 -0
- data/Rakefile +55 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/xrechnung.rb +326 -0
- data/lib/xrechnung/allowance_charge.rb +32 -0
- data/lib/xrechnung/contact.rb +26 -0
- data/lib/xrechnung/currency.rb +22 -0
- data/lib/xrechnung/id.rb +3 -0
- data/lib/xrechnung/invoice_document_reference.rb +20 -0
- data/lib/xrechnung/invoice_line.rb +41 -0
- data/lib/xrechnung/item.rb +40 -0
- data/lib/xrechnung/legal_monetary_total.rb +51 -0
- data/lib/xrechnung/member_container.rb +68 -0
- data/lib/xrechnung/party.rb +61 -0
- data/lib/xrechnung/party_legal_entity.rb +16 -0
- data/lib/xrechnung/party_tax_scheme.rb +23 -0
- data/lib/xrechnung/payee_financial_account.rb +35 -0
- data/lib/xrechnung/payment_means.rb +29 -0
- data/lib/xrechnung/postal_address.rb +44 -0
- data/lib/xrechnung/price.rb +31 -0
- data/lib/xrechnung/quantity.rb +12 -0
- data/lib/xrechnung/tax_category.rb +43 -0
- data/lib/xrechnung/tax_subtotal.rb +47 -0
- data/lib/xrechnung/tax_total.rb +46 -0
- data/lib/xrechnung/version.rb +3 -0
- data/xrechnung.gemspec +29 -0
- metadata +122 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
module Xrechnung
|
2
|
+
class AllowanceCharge
|
3
|
+
include MemberContainer
|
4
|
+
|
5
|
+
# @!attribute charge_indicator
|
6
|
+
# @return [TrueClass, FalseClass]
|
7
|
+
member :charge_indicator, type: [TrueClass, FalseClass]
|
8
|
+
|
9
|
+
# @!attribute amount
|
10
|
+
# @return [Xrechnung::Currency]
|
11
|
+
member :amount, type: Xrechnung::Currency
|
12
|
+
|
13
|
+
# @!attribute base_amount
|
14
|
+
# @return [Xrechnung::Currency]
|
15
|
+
member :base_amount, type: Xrechnung::Currency
|
16
|
+
|
17
|
+
def initialize(**kwargs)
|
18
|
+
kwargs[:amount] = Currency::EUR(kwargs[:amount])
|
19
|
+
kwargs[:base_amount] = Currency::EUR(kwargs[:base_amount])
|
20
|
+
super(**kwargs)
|
21
|
+
end
|
22
|
+
|
23
|
+
# noinspection RubyResolve
|
24
|
+
def to_xml(xml)
|
25
|
+
xml.cac :AllowanceCharge do
|
26
|
+
xml.cbc :ChargeIndicator, charge_indicator
|
27
|
+
xml.cbc :Amount, *amount.xml_args
|
28
|
+
xml.cbc :BaseAmount, *base_amount.xml_args
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Xrechnung
|
2
|
+
class Contact
|
3
|
+
include MemberContainer
|
4
|
+
|
5
|
+
# @!attribute name
|
6
|
+
# @return [String]
|
7
|
+
member :name, type: String
|
8
|
+
|
9
|
+
# @!attribute telephone
|
10
|
+
# @return [String]
|
11
|
+
member :telephone, type: String
|
12
|
+
|
13
|
+
# @!attribute electronic_mail
|
14
|
+
# @return [String]
|
15
|
+
member :electronic_mail, type: String
|
16
|
+
|
17
|
+
# noinspection RubyResolve
|
18
|
+
def to_xml(xml)
|
19
|
+
xml.cac :Contact do
|
20
|
+
xml.cbc :Name, name
|
21
|
+
xml.cbc :Telephone, telephone
|
22
|
+
xml.cbc :ElectronicMail, electronic_mail
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "bigdecimal"
|
2
|
+
require "bigdecimal/util"
|
3
|
+
|
4
|
+
module Xrechnung
|
5
|
+
Currency = Struct.new(:currency_id, :value, keyword_init: true) do
|
6
|
+
def value_to_s
|
7
|
+
format("%0.2f", value)
|
8
|
+
end
|
9
|
+
|
10
|
+
def xml_args
|
11
|
+
[value_to_s, currencyID: currency_id]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class << Currency
|
16
|
+
def EUR(value)
|
17
|
+
raise ArgumentError, "value must respond to :to_d" unless value.respond_to? :to_d
|
18
|
+
|
19
|
+
Currency.new(currency_id: "EUR", value: value.to_d)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/xrechnung/id.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Xrechnung
|
2
|
+
class InvoiceDocumentReference
|
3
|
+
include MemberContainer
|
4
|
+
|
5
|
+
# @!attribute id
|
6
|
+
# @return [String]
|
7
|
+
member :id, type: String
|
8
|
+
|
9
|
+
# @!attribute issue_date
|
10
|
+
# @return [Date]
|
11
|
+
member :issue_date, type: Date
|
12
|
+
|
13
|
+
def to_xml(xml)
|
14
|
+
xml.cac :InvoiceDocumentReference do
|
15
|
+
xml.cbc :ID, id
|
16
|
+
xml.cbc :IssueDate, issue_date
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Xrechnung
|
2
|
+
class InvoiceLine
|
3
|
+
include MemberContainer
|
4
|
+
|
5
|
+
# @!attribute id
|
6
|
+
# @return [Integer]
|
7
|
+
member :id, type: Integer
|
8
|
+
|
9
|
+
# @!attribute invoiced_quantity
|
10
|
+
# @return [Xrechnung::Quantity]
|
11
|
+
member :invoiced_quantity, type: Xrechnung::Quantity
|
12
|
+
|
13
|
+
# @!attribute line_extension_amount
|
14
|
+
# @return [Xrechnung::Currency]
|
15
|
+
member :line_extension_amount, type: Xrechnung::Currency
|
16
|
+
|
17
|
+
# @!attribute item
|
18
|
+
# @return [Xrechnung::Item]
|
19
|
+
member :item, type: Xrechnung::Item
|
20
|
+
|
21
|
+
# @!attribute price
|
22
|
+
# @return [Xrechnung::Price]
|
23
|
+
member :price, type: Xrechnung::Price
|
24
|
+
|
25
|
+
def initialize(**kwargs)
|
26
|
+
kwargs[:line_extension_amount] = Currency::EUR(kwargs[:line_extension_amount])
|
27
|
+
super(**kwargs)
|
28
|
+
end
|
29
|
+
|
30
|
+
# noinspection RubyResolve
|
31
|
+
def to_xml(xml)
|
32
|
+
xml.cac :InvoiceLine do
|
33
|
+
xml.cbc :ID, id
|
34
|
+
xml.cbc :InvoicedQuantity, invoiced_quantity.amount_to_s, unitCode: invoiced_quantity.unit_code
|
35
|
+
xml.cbc :LineExtensionAmount, *line_extension_amount.xml_args
|
36
|
+
item&.to_xml(xml)
|
37
|
+
price&.to_xml(xml)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Xrechnung
|
2
|
+
class Item
|
3
|
+
include MemberContainer
|
4
|
+
|
5
|
+
# @!attribute description
|
6
|
+
# @return [String]
|
7
|
+
member :description, type: String
|
8
|
+
|
9
|
+
# @!attribute name
|
10
|
+
# @return [String]
|
11
|
+
member :name, type: String
|
12
|
+
|
13
|
+
# @!attribute standard_item_identification_id
|
14
|
+
# @return [Xrechnung::Id]
|
15
|
+
member :standard_item_identification_id, type: Xrechnung::Id, optional: true
|
16
|
+
|
17
|
+
# @!attribute commodity_classification
|
18
|
+
# @return [Xrechnung::TaxCategory]
|
19
|
+
member :commodity_classification, type: Xrechnung::TaxCategory
|
20
|
+
|
21
|
+
# @!attribute classified_tax_category
|
22
|
+
# @return [Xrechnung::TaxCategory]
|
23
|
+
member :classified_tax_category, type: Xrechnung::TaxCategory
|
24
|
+
|
25
|
+
# noinspection RubyResolve
|
26
|
+
def to_xml(xml)
|
27
|
+
xml.cac :Item do
|
28
|
+
xml.cbc :Description, description
|
29
|
+
xml.cbc :Name, name
|
30
|
+
unless standard_item_identification_id.nil?
|
31
|
+
xml.cac :StandardItemIdentification do
|
32
|
+
xml.cbc :ID, standard_item_identification_id.id, schemeID: standard_item_identification_id.scheme_id
|
33
|
+
end
|
34
|
+
end
|
35
|
+
xml.cac :CommodityClassification, commodity_classification
|
36
|
+
classified_tax_category&.to_xml(xml, root_tag_name: :ClassifiedTaxCategory)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Xrechnung
|
2
|
+
class LegalMonetaryTotal
|
3
|
+
include MemberContainer
|
4
|
+
|
5
|
+
transform_currency = ->(v) {
|
6
|
+
Currency::EUR(v)
|
7
|
+
}
|
8
|
+
|
9
|
+
# @!attribute line_extension_amount
|
10
|
+
# @return [Xrechnung::Currency]
|
11
|
+
member :line_extension_amount, type: Xrechnung::Currency, transform_value: transform_currency
|
12
|
+
|
13
|
+
# @!attribute tax_exclusive_amount
|
14
|
+
# @return [Xrechnung::Currency]
|
15
|
+
member :tax_exclusive_amount, type: Xrechnung::Currency, transform_value: transform_currency
|
16
|
+
|
17
|
+
# @!attribute tax_inclusive_amount
|
18
|
+
# @return [Xrechnung::Currency]
|
19
|
+
member :tax_inclusive_amount, type: Xrechnung::Currency, transform_value: transform_currency
|
20
|
+
|
21
|
+
# @!attribute allowance_total_amount
|
22
|
+
# @return [Xrechnung::Currency]
|
23
|
+
member :allowance_total_amount, type: Xrechnung::Currency, transform_value: transform_currency
|
24
|
+
|
25
|
+
# @!attribute charge_total_amount
|
26
|
+
# @return [Xrechnung::Currency]
|
27
|
+
member :charge_total_amount, type: Xrechnung::Currency, transform_value: transform_currency
|
28
|
+
|
29
|
+
# @!attribute prepaid_amount
|
30
|
+
# @return [Xrechnung::Currency]
|
31
|
+
member :prepaid_amount, type: Xrechnung::Currency, transform_value: transform_currency
|
32
|
+
|
33
|
+
# @!attribute payable_rounding_amount
|
34
|
+
# @return [Xrechnung::Currency]
|
35
|
+
member :payable_rounding_amount, type: Xrechnung::Currency, transform_value: transform_currency
|
36
|
+
|
37
|
+
# @!attribute payable_amount
|
38
|
+
# @return [Xrechnung::Currency]
|
39
|
+
member :payable_amount, type: Xrechnung::Currency, transform_value: transform_currency
|
40
|
+
|
41
|
+
# noinspection RubyResolve
|
42
|
+
def to_xml(xml)
|
43
|
+
members.each do |member, _options|
|
44
|
+
next if self[member].nil?
|
45
|
+
|
46
|
+
xml.cbc :"#{member.to_s.split("_").map(&:capitalize).join}", *self[member].xml_args
|
47
|
+
end
|
48
|
+
xml.target!
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Xrechnung
|
2
|
+
module MemberContainer
|
3
|
+
def self.included(base)
|
4
|
+
base.instance_variable_set :@members, {}
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(**kwargs)
|
9
|
+
self.class.after_initialize.each do |block|
|
10
|
+
instance_eval(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
kwargs.each do |k, v|
|
14
|
+
self[k] = v
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def members
|
19
|
+
self.class.instance_variable_get :@members
|
20
|
+
end
|
21
|
+
|
22
|
+
def [](key)
|
23
|
+
send(key)
|
24
|
+
end
|
25
|
+
|
26
|
+
def []=(key, value)
|
27
|
+
send(members[key].fetch(:setter_name), value)
|
28
|
+
end
|
29
|
+
|
30
|
+
module ClassMethods
|
31
|
+
# @param [String] member_name
|
32
|
+
# @param [Array<Class>, Class] type
|
33
|
+
# @param [Object] default
|
34
|
+
# @param [TrueClass, FalseClass] optional When true, omits tag rather than rendering an empty tag on nil
|
35
|
+
# @param [Proc] transform_value A Proc which is called with the input value to perform type conversion.
|
36
|
+
def member(member_name, type: nil, default: nil, optional: false, transform_value: nil)
|
37
|
+
attr_reader member_name
|
38
|
+
setter_name = :"#{member_name}="
|
39
|
+
@members[member_name] = { optional: optional, setter_name: setter_name }
|
40
|
+
|
41
|
+
if default
|
42
|
+
after_initialize do
|
43
|
+
send(setter_name, default)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
define_method setter_name do |in_value|
|
48
|
+
in_value = transform_value.call(in_value) if transform_value
|
49
|
+
|
50
|
+
if type && !in_value.nil? && Array(type).none? { |t| in_value.is_a?(t) }
|
51
|
+
raise ArgumentError, "expected #{type} for :#{member_name}, got: #{in_value.class}"
|
52
|
+
end
|
53
|
+
|
54
|
+
instance_variable_set :"@#{member_name}", in_value
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def after_initialize(&block)
|
59
|
+
@after_initialize_blocks ||= []
|
60
|
+
if block
|
61
|
+
@after_initialize_blocks << block
|
62
|
+
else
|
63
|
+
@after_initialize_blocks
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Xrechnung
|
2
|
+
class Party
|
3
|
+
include MemberContainer
|
4
|
+
|
5
|
+
# @!attribute name
|
6
|
+
# @return [String]
|
7
|
+
member :name, type: String
|
8
|
+
|
9
|
+
# @!attribute postal_address
|
10
|
+
# @return [Xrechnung::PostalAddress]
|
11
|
+
member :postal_address, type: Xrechnung::PostalAddress
|
12
|
+
|
13
|
+
# @!attribute party_tax_scheme
|
14
|
+
# @return [Xrechnung::PartyTaxScheme]
|
15
|
+
member :party_tax_scheme, type: Xrechnung::PartyTaxScheme
|
16
|
+
|
17
|
+
# @!attribute party_legal_entity
|
18
|
+
# @return [Xrechnung::PartyLegalEntity]
|
19
|
+
member :party_legal_entity, type: Xrechnung::PartyLegalEntity
|
20
|
+
|
21
|
+
# @!attribute contact
|
22
|
+
# @return [Xrechnung::Contact]
|
23
|
+
member :contact, type: Xrechnung::Contact
|
24
|
+
|
25
|
+
attr_accessor :nested
|
26
|
+
|
27
|
+
def initialize(nested: true, **kwargs)
|
28
|
+
super(**kwargs)
|
29
|
+
self.nested = nested
|
30
|
+
end
|
31
|
+
|
32
|
+
# noinspection RubyResolve
|
33
|
+
def to_xml(xml)
|
34
|
+
if nested
|
35
|
+
xml.cac :Party do
|
36
|
+
party_body(xml)
|
37
|
+
end
|
38
|
+
else
|
39
|
+
party_body(xml)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def party_body(xml)
|
46
|
+
unless name.nil? # if blank? -> empty name tag
|
47
|
+
xml.cac :PartyName do
|
48
|
+
if name == ""
|
49
|
+
xml.cbc :Name
|
50
|
+
else
|
51
|
+
xml.cbc :Name, name
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
postal_address&.to_xml(xml)
|
56
|
+
party_tax_scheme&.to_xml(xml)
|
57
|
+
party_legal_entity&.to_xml(xml)
|
58
|
+
contact&.to_xml(xml)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Xrechnung
|
2
|
+
class PartyLegalEntity
|
3
|
+
include MemberContainer
|
4
|
+
|
5
|
+
# @!attribute registration_name
|
6
|
+
# @return [String]
|
7
|
+
member :registration_name, type: String
|
8
|
+
|
9
|
+
# noinspection RubyResolve
|
10
|
+
def to_xml(xml)
|
11
|
+
xml.cac :PartyLegalEntity do
|
12
|
+
xml.cbc :RegistrationName, registration_name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Xrechnung
|
2
|
+
class PartyTaxScheme
|
3
|
+
include MemberContainer
|
4
|
+
|
5
|
+
# @!attribute company_id
|
6
|
+
# @return [String]
|
7
|
+
member :company_id, type: String
|
8
|
+
|
9
|
+
# @!attribute tax_scheme_id
|
10
|
+
# @return [String]
|
11
|
+
member :tax_scheme_id, type: String, default: "VAT"
|
12
|
+
|
13
|
+
# noinspection RubyResolve
|
14
|
+
def to_xml(xml)
|
15
|
+
xml.cac :PartyTaxScheme do
|
16
|
+
xml.cbc :CompanyID, company_id
|
17
|
+
xml.cac :TaxScheme do
|
18
|
+
xml.cbc :ID, tax_scheme_id
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Xrechnung
|
2
|
+
# <cac:PayeeFinancialAccount>
|
3
|
+
# <cbc:ID>DE12500105170648489890</cbc:ID>
|
4
|
+
# <cbc:Name>Harry Hirsch</cbc:Name>
|
5
|
+
# <cac:FinancialInstitutionBranch>
|
6
|
+
# <cbc:ID>XUFUXHB</cbc:ID>
|
7
|
+
# </cac:FinancialInstitutionBranch>
|
8
|
+
# </cac:PayeeFinancialAccount>
|
9
|
+
class PayeeFinancialAccount
|
10
|
+
include MemberContainer
|
11
|
+
|
12
|
+
# @!attribute id
|
13
|
+
# @return [String]
|
14
|
+
member :id, type: String
|
15
|
+
|
16
|
+
# @!attribute name
|
17
|
+
# @return [String]
|
18
|
+
member :name, type: String
|
19
|
+
|
20
|
+
# @!attribute financial_institution_branch_id
|
21
|
+
# @return [String]
|
22
|
+
member :financial_institution_branch_id, type: String
|
23
|
+
|
24
|
+
# noinspection RubyResolve
|
25
|
+
def to_xml(xml)
|
26
|
+
xml.cac :PayeeFinancialAccount do
|
27
|
+
xml.cbc :ID, id
|
28
|
+
xml.cbc :Name, name
|
29
|
+
xml.cac :FinancialInstitutionBranch do
|
30
|
+
xml.cbc :ID, financial_institution_branch_id
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|