xrechnung 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,3 @@
1
+ module Xrechnung
2
+ Id = Struct.new(:id, :scheme_id)
3
+ end
@@ -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