einvoicing 0.2.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +55 -0
- data/README.md +277 -0
- data/config/locales/einvoicing.en.yml +27 -0
- data/config/locales/einvoicing.fr.yml +27 -0
- data/lib/einvoicing/data/srgb.icc +0 -0
- data/lib/einvoicing/formats/cii.rb +218 -0
- data/lib/einvoicing/formats/facturx.rb +195 -0
- data/lib/einvoicing/formats/ubl.rb +226 -0
- data/lib/einvoicing/i18n.rb +22 -0
- data/lib/einvoicing/invoice.rb +99 -0
- data/lib/einvoicing/invoiceable.rb +120 -0
- data/lib/einvoicing/line_item.rb +54 -0
- data/lib/einvoicing/party.rb +29 -0
- data/lib/einvoicing/ppf/client.rb +117 -0
- data/lib/einvoicing/ppf/errors.rb +12 -0
- data/lib/einvoicing/ppf/invoice_adapter.rb +61 -0
- data/lib/einvoicing/ppf/submitter.rb +32 -0
- data/lib/einvoicing/ppf.rb +6 -0
- data/lib/einvoicing/rails/concern.rb +4 -0
- data/lib/einvoicing/rails/engine.rb +21 -0
- data/lib/einvoicing/tax.rb +38 -0
- data/lib/einvoicing/validators/base.rb +52 -0
- data/lib/einvoicing/validators/fr.rb +191 -0
- data/lib/einvoicing/version.rb +1 -1
- data/lib/einvoicing/xml_builder.rb +67 -0
- data/lib/einvoicing.rb +45 -5
- metadata +135 -8
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Einvoicing
|
|
4
|
+
# Minimal zero-dependency XML builder used internally by format generators.
|
|
5
|
+
# Produces indented XML with proper attribute and text escaping.
|
|
6
|
+
class XMLBuilder
|
|
7
|
+
def initialize
|
|
8
|
+
@parts = ['<?xml version="1.0" encoding="UTF-8"?>']
|
|
9
|
+
@depth = 0
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Build a non-empty element with an optional block for children.
|
|
13
|
+
# If the block yields no content, the element is omitted entirely.
|
|
14
|
+
def tag(name, attrs = {}, &block)
|
|
15
|
+
attr_str = serialize_attrs(attrs)
|
|
16
|
+
if block
|
|
17
|
+
opening = "#{indent}<#{name}#{attr_str}>"
|
|
18
|
+
@parts << opening
|
|
19
|
+
size_before = @parts.size
|
|
20
|
+
@depth += 1
|
|
21
|
+
yield
|
|
22
|
+
@depth -= 1
|
|
23
|
+
if @parts.size == size_before
|
|
24
|
+
# Block yielded nothing — remove the opening tag.
|
|
25
|
+
@parts.pop
|
|
26
|
+
else
|
|
27
|
+
@parts << "#{indent}</#{name}>"
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
@parts << "#{indent}<#{name}#{attr_str}/>"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Build a text element: <Name>value</Name>.
|
|
35
|
+
def text(name, value, attrs = {})
|
|
36
|
+
return if value.nil?
|
|
37
|
+
|
|
38
|
+
attr_str = serialize_attrs(attrs)
|
|
39
|
+
@parts << "#{indent}<#{name}#{attr_str}>#{escape(value.to_s)}</#{name}>"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def to_xml
|
|
43
|
+
@parts.join("\n")
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def indent
|
|
49
|
+
" " * @depth
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def escape(str)
|
|
53
|
+
str
|
|
54
|
+
.gsub("&", "&")
|
|
55
|
+
.gsub("<", "<")
|
|
56
|
+
.gsub(">", ">")
|
|
57
|
+
.gsub('"', """)
|
|
58
|
+
.gsub("'", "'")
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def serialize_attrs(attrs)
|
|
62
|
+
return "" if attrs.empty?
|
|
63
|
+
|
|
64
|
+
attrs.map { |k, v| %( #{k}="#{escape(v.to_s)}") }.join
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
data/lib/einvoicing.rb
CHANGED
|
@@ -1,10 +1,50 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "date"
|
|
4
|
+
require "bigdecimal"
|
|
5
|
+
require "bigdecimal/util"
|
|
6
|
+
|
|
3
7
|
require_relative "einvoicing/version"
|
|
8
|
+
require_relative "einvoicing/tax"
|
|
9
|
+
require_relative "einvoicing/party"
|
|
10
|
+
require_relative "einvoicing/line_item"
|
|
11
|
+
require_relative "einvoicing/invoice"
|
|
12
|
+
require_relative "einvoicing/xml_builder"
|
|
13
|
+
require_relative "einvoicing/formats/cii"
|
|
14
|
+
require_relative "einvoicing/formats/ubl"
|
|
15
|
+
require_relative "einvoicing/formats/facturx"
|
|
16
|
+
require_relative "einvoicing/i18n"
|
|
17
|
+
require_relative "einvoicing/validators/base"
|
|
18
|
+
require_relative "einvoicing/validators/fr"
|
|
19
|
+
require_relative "einvoicing/invoiceable"
|
|
20
|
+
require_relative "einvoicing/rails/concern"
|
|
21
|
+
require_relative "einvoicing/ppf"
|
|
22
|
+
|
|
23
|
+
# Optional Rails engine — only load when Rails is available.
|
|
24
|
+
if defined?(Rails::Engine)
|
|
25
|
+
require_relative "einvoicing/rails/engine"
|
|
26
|
+
end
|
|
4
27
|
|
|
5
|
-
#
|
|
6
|
-
#
|
|
28
|
+
# Einvoicing — EU electronic invoicing for Ruby.
|
|
29
|
+
#
|
|
30
|
+
# Generates EN 16931-compliant invoices in Factur-X (PDF/A-3 + CII XML),
|
|
31
|
+
# UBL 2.1, and CII D16B formats. Validates French B2B compliance (SIREN,
|
|
32
|
+
# SIRET, TVA). Provides a Rails concern for ActiveRecord models.
|
|
33
|
+
#
|
|
34
|
+
# @example Quick start
|
|
35
|
+
# seller = Einvoicing::Party.new(name: "Acme SAS", siren: "356000000", vat_number: "FR83356000000")
|
|
36
|
+
# buyer = Einvoicing::Party.new(name: "Client SA", siren: "552032534")
|
|
37
|
+
# line = Einvoicing::LineItem.new(description: "Consulting", quantity: 1, unit_price: 1000.00)
|
|
38
|
+
#
|
|
39
|
+
# invoice = Einvoicing::Invoice.new(
|
|
40
|
+
# invoice_number: "INV-2024-001",
|
|
41
|
+
# issue_date: Date.today,
|
|
42
|
+
# seller: seller,
|
|
43
|
+
# buyer: buyer,
|
|
44
|
+
# lines: [line]
|
|
45
|
+
# )
|
|
7
46
|
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
|
|
47
|
+
# xml = Einvoicing::Formats::CII.generate(invoice)
|
|
48
|
+
# ubl = Einvoicing::Formats::UBL.generate(invoice)
|
|
49
|
+
module Einvoicing
|
|
50
|
+
end
|
metadata
CHANGED
|
@@ -1,28 +1,154 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: einvoicing
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nathan Le Ray
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: bin
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
-
dependencies:
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
date: 2026-03-13 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: hexapdf
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.0'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rspec
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '3.13'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '3.13'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rubocop
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.65'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.65'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: nokogiri
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '1.16'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '1.16'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: rexml
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :development
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: prawn
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '0'
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - ">="
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: webmock
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '3.0'
|
|
104
|
+
type: :development
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '3.0'
|
|
111
|
+
description: |
|
|
112
|
+
EN 16931-compliant e-invoicing for Ruby. Generates Factur-X (PDF/A-3 + CII XML),
|
|
113
|
+
UBL 2.1, and CII D16B. Validates French B2B requirements (SIREN, SIRET, TVA).
|
|
114
|
+
Rails concern for ActiveRecord models. Targets French September 2026 mandate.
|
|
14
115
|
email:
|
|
15
|
-
-
|
|
116
|
+
- nathan@sxnlabs.com
|
|
16
117
|
executables: []
|
|
17
118
|
extensions: []
|
|
18
119
|
extra_rdoc_files: []
|
|
19
120
|
files:
|
|
121
|
+
- CHANGELOG.md
|
|
122
|
+
- README.md
|
|
123
|
+
- config/locales/einvoicing.en.yml
|
|
124
|
+
- config/locales/einvoicing.fr.yml
|
|
20
125
|
- lib/einvoicing.rb
|
|
126
|
+
- lib/einvoicing/data/srgb.icc
|
|
127
|
+
- lib/einvoicing/formats/cii.rb
|
|
128
|
+
- lib/einvoicing/formats/facturx.rb
|
|
129
|
+
- lib/einvoicing/formats/ubl.rb
|
|
130
|
+
- lib/einvoicing/i18n.rb
|
|
131
|
+
- lib/einvoicing/invoice.rb
|
|
132
|
+
- lib/einvoicing/invoiceable.rb
|
|
133
|
+
- lib/einvoicing/line_item.rb
|
|
134
|
+
- lib/einvoicing/party.rb
|
|
135
|
+
- lib/einvoicing/ppf.rb
|
|
136
|
+
- lib/einvoicing/ppf/client.rb
|
|
137
|
+
- lib/einvoicing/ppf/errors.rb
|
|
138
|
+
- lib/einvoicing/ppf/invoice_adapter.rb
|
|
139
|
+
- lib/einvoicing/ppf/submitter.rb
|
|
140
|
+
- lib/einvoicing/rails/concern.rb
|
|
141
|
+
- lib/einvoicing/rails/engine.rb
|
|
142
|
+
- lib/einvoicing/tax.rb
|
|
143
|
+
- lib/einvoicing/validators/base.rb
|
|
144
|
+
- lib/einvoicing/validators/fr.rb
|
|
21
145
|
- lib/einvoicing/version.rb
|
|
146
|
+
- lib/einvoicing/xml_builder.rb
|
|
22
147
|
homepage: https://github.com/sxnlabs/einvoicing
|
|
23
148
|
licenses:
|
|
24
149
|
- MIT
|
|
25
150
|
metadata: {}
|
|
151
|
+
post_install_message:
|
|
26
152
|
rdoc_options: []
|
|
27
153
|
require_paths:
|
|
28
154
|
- lib
|
|
@@ -37,7 +163,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
37
163
|
- !ruby/object:Gem::Version
|
|
38
164
|
version: '0'
|
|
39
165
|
requirements: []
|
|
40
|
-
rubygems_version:
|
|
166
|
+
rubygems_version: 3.5.22
|
|
167
|
+
signing_key:
|
|
41
168
|
specification_version: 4
|
|
42
|
-
summary: EU electronic invoicing for Ruby — EN 16931, Factur-X, UBL 2.1
|
|
169
|
+
summary: EU electronic invoicing for Ruby — EN 16931, Factur-X, UBL 2.1
|
|
43
170
|
test_files: []
|