factur-x-builder 0.1.2 → 0.1.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2f380d59a7b981bd4999314d3321a99dc762ac9c67709f6e543cc5632eade2c4
4
- data.tar.gz: 553e1dda58b31b9804ede1acc9c75ff4ee515b1bcf152a508fb56bca7ebf2357
3
+ metadata.gz: da7a9bafbb80d9e9ac88ee325e49b76c1855e91774f3a1bf1c4dacdcf679cdc9
4
+ data.tar.gz: 729c3209aa5378bbde0b2400c797db122d887a34cb370d588c22e61df9a94d0b
5
5
  SHA512:
6
- metadata.gz: 54363eb24098df15598c699e48956247464bc739435af190736762e0707b77513f98e12b836db743e832b98672ef989fc225833c08ab06402b391bd10474f83d
7
- data.tar.gz: 71355fc896353819a7d66da2b3d1fb078f251184858add396e3d25bc6475535c6eb7593ffeb6ec23b48fb4900e9fe8a76440b8576e10dc20173c41e556461223
6
+ metadata.gz: bd23212eaeb87434500c7f45b41708b1bb9f72bea9f8c178a35953194d0503a41d939e0f36db9b24ae0ba1ace8bdb79035905e70516d0886f54c3af52da26b3a
7
+ data.tar.gz: 362f6dfba5482d591a1131e866e29ffbf1300873fe2aa73841f65ce3e36b829a8b417c3376cf4fbfc5a2fca6e0038159103b372d9e4a3e10d8907fb1dea55a4c
data/.rubocop.yml CHANGED
@@ -27,3 +27,6 @@ Style/StringLiteralsInInterpolation:
27
27
 
28
28
  Layout/LineLength:
29
29
  Max: 120
30
+
31
+ Gemspec/RequireMFA:
32
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## [Unreleased]
2
+
3
+ ### Added
4
+
5
+ - A credit note is now checked against BR-FR-CO-05: it must reference the invoice it corrects with
6
+ both the number (BT-25) and the issue date (BT-26). A reference missing its date failed the
7
+ French schematron exactly like an absent one, and neither was caught before generating.
8
+ `Codes::CREDIT_NOTE_TYPES` names the document types the rule applies to.
9
+
1
10
  ## [0.1.2] - 2026-08-15
2
11
 
3
12
  ### Added
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- factur-x-builder (0.1.1)
4
+ factur-x-builder (0.1.4)
5
5
  nokogiri (~> 1.15, < 1.16)
6
6
 
7
7
  GEM
@@ -12,6 +12,8 @@ GEM
12
12
  language_server-protocol (3.17.0.6)
13
13
  lint_roller (1.1.0)
14
14
  minitest (5.26.1)
15
+ nokogiri (1.15.7-arm64-darwin)
16
+ racc (~> 1.4)
15
17
  nokogiri (1.15.7-x86_64-darwin)
16
18
  racc (~> 1.4)
17
19
  parallel (1.28.0)
@@ -43,6 +45,7 @@ GEM
43
45
  unicode-emoji (4.2.0)
44
46
 
45
47
  PLATFORMS
48
+ arm64-darwin-25
46
49
  x86_64-darwin-21
47
50
 
48
51
  DEPENDENCIES
data/README.md CHANGED
@@ -133,6 +133,41 @@ anything is generated.
133
133
  A credit note carries **positive** amounts; the type code conveys the direction. Negative unit
134
134
  prices are rejected (`BR-27`, `BR-28`).
135
135
 
136
+ Cancelling invoice A with credit note B changes four things and nothing else — B's own number
137
+ (BT-1) and issue date (BT-2), the type code `381` (BT-3), and a reference to A carrying **both** its
138
+ number and its issue date (BG-3). That reference is required by the French profile (`BR-FR-CO-05`)
139
+ though not by EN 16931 alone, and a reference without a date fails just like a missing one. Parties,
140
+ lines, prices, VAT breakdown and totals are copied over untouched.
141
+
142
+ ```ruby
143
+ FacturX::Invoice.new(
144
+ number: "AV-2026-0012",
145
+ issued_on: Date.today,
146
+ type_code: FacturX::Codes::CREDIT_NOTE,
147
+ preceding_invoices: [
148
+ FacturX::ReferencedInvoice.new(number: "5-2026-0004", issued_on: Date.new(2026, 8, 4))
149
+ ],
150
+ # … everything else identical to the invoice being cancelled
151
+ )
152
+ ```
153
+
154
+ ### Routing address
155
+
156
+ `routing_id` is the electronic address the platform delivers to (BT-34 for the seller, BT-49 for the
157
+ buyer). It defaults to the SIRET, and its scheme identifier — mandatory under BR-62 and BR-63 — is
158
+ filled in as `0225`.
159
+
160
+ That code designates the addressing of the French reform itself, not a particular identifier, so it
161
+ stays `0225` whatever the directory registered: SIREN, SIRET, `SIREN_SIRET`, or
162
+ `SIREN_SIRET_CODE_ROUTAGE` for an address finer than the establishment. The value is opaque to the
163
+ gem — forwarded verbatim, never parsed — and every shape is covered by the conformance suite.
164
+
165
+ ```ruby
166
+ FacturX::Party.new(name: "…", siret: "39876543800005",
167
+ routing_id: "398765438_39876543800005_COMPTA")
168
+ # => <ram:URIID schemeID="0225">398765438_39876543800005_COMPTA</ram:URIID>
169
+ ```
170
+
136
171
  ### Payment instructions are optional
137
172
 
138
173
  `payment_means` maps to BG-16 *Payment instructions*, which both schematrons accept as absent. It
@@ -10,6 +10,11 @@ module FacturX
10
10
 
11
11
  DOCUMENT_TYPES = [COMMERCIAL_INVOICE, CREDIT_NOTE, SELF_BILLED_INVOICE].freeze
12
12
 
13
+ # The document types BR-FR-CO-05 treats as credit notes. Only 381 is
14
+ # emitted by this gem; the others are listed so the rule keeps matching
15
+ # if DOCUMENT_TYPES ever widens.
16
+ CREDIT_NOTE_TYPES = %w[261 381 396 502 503].freeze
17
+
13
18
  # Invoicing modes accepted by the French e-invoicing reform (BR-FR-08).
14
19
  BUSINESS_PROCESSES = %w[B1 S1 M1 B2 S2 M2 S3 B4 S4 M4 S5 S6 B7 S7 B8 S8 M8 B9 S9 M9].freeze
15
20
 
@@ -10,6 +10,12 @@ module FacturX
10
10
  # `routing_id` the electronic address (scheme 0225) used to route the
11
11
  # invoice through the PPF, defaulting to the SIRET.
12
12
  #
13
+ # Scheme 0225 designates the addressing of the French reform itself, not a
14
+ # particular identifier, so it holds whatever shape the directory registered:
15
+ # SIREN, SIRET, SIREN_SIRET, or SIREN_SIRET_CODE_ROUTAGE for an address finer
16
+ # than the establishment. The value is opaque here - it is forwarded verbatim,
17
+ # never parsed - so a new directory shape needs no change to this gem.
18
+ #
13
19
  # `legal_information` is BT-33, the seller's additional legal information:
14
20
  # legal form, share capital, RCS registration, and any other statement the
15
21
  # printed invoice must carry. A party holds a single postal address, so this
@@ -91,6 +91,21 @@ module FacturX
91
91
  "notes (BT-22 with subject code #{code}, BR-FR-05) - " \
92
92
  "Note.french_legal_mentions provides the three of them")
93
93
  end
94
+
95
+ check_corrected_invoice
96
+ end
97
+
98
+ # BR-FR-CO-05: a credit note must say which invoice it corrects. EN 16931
99
+ # alone is happy without it, the French profile is not. The number and the
100
+ # issue date are both required - a reference carrying only the number
101
+ # fails the rule just as an absent one does.
102
+ def check_corrected_invoice
103
+ return unless Codes::CREDIT_NOTE_TYPES.include?(invoice.type_code)
104
+ return if invoice.preceding_invoices.any? { |ref| !blank?(ref.number) && !ref.issued_on.nil? }
105
+
106
+ add("a credit note must reference the invoice it corrects, with both its number and " \
107
+ "its issue date (BT-25 and BT-26, BR-FR-CO-05) - pass preceding_invoices: " \
108
+ "[ReferencedInvoice.new(number:, issued_on:)]")
94
109
  end
95
110
 
96
111
  def check_document
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FacturX
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.4"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: factur-x-builder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hotentic
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-08-15 00:00:00.000000000 Z
11
+ date: 2026-09-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri