edi4r 0.9.4.1 → 0.9.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/AuthorCopyright +3 -3
- data/{ChangeLog → Changelog} +60 -0
- data/README +15 -10
- data/Tutorial +2 -3
- data/VERSION +1 -1
- data/bin/edi2xml.rb +12 -16
- data/bin/editool.rb +9 -5
- data/bin/sedas2eancom02.rb +1385 -0
- data/bin/xml2edi.rb +7 -12
- data/data/edifact/iso9735/SDCD.20000.csv +1 -0
- data/data/edifact/iso9735/SDCD.3for2.csv +1 -0
- data/data/edifact/iso9735/SDED.20000.csv +6 -0
- data/data/edifact/iso9735/SDED.30000.csv +43 -43
- data/data/edifact/iso9735/SDED.3for2.csv +6 -0
- data/data/edifact/iso9735/SDED.40000.csv +129 -129
- data/data/edifact/iso9735/SDED.40100.csv +130 -130
- data/data/edifact/iso9735/SDMD.20000.csv +6 -0
- data/data/edifact/iso9735/SDMD.30000.csv +6 -6
- data/data/edifact/iso9735/SDMD.3for2.csv +6 -0
- data/data/edifact/iso9735/SDMD.40000.csv +17 -17
- data/data/edifact/iso9735/SDMD.40100.csv +17 -17
- data/data/edifact/iso9735/SDSD.20000.csv +5 -0
- data/data/edifact/iso9735/SDSD.3for2.csv +5 -0
- data/data/edifact/untdid/EDMD.d01b.csv +1 -1
- data/data/sedas/EDCD..csv +0 -0
- data/data/sedas/EDED..csv +859 -0
- data/data/sedas/EDMD..csv +16 -0
- data/data/sedas/EDSD..csv +44 -0
- data/lib/edi4r.rb +147 -67
- data/lib/edi4r/ansi_x12-rexml.rb +91 -0
- data/lib/edi4r/ansi_x12.rb +1684 -0
- data/lib/edi4r/diagrams.rb +75 -14
- data/lib/edi4r/edifact-rexml.rb +4 -3
- data/lib/edi4r/edifact.rb +505 -202
- data/lib/edi4r/rexml.rb +13 -7
- data/lib/edi4r/sedas.rb +854 -0
- data/lib/edi4r/standards.rb +150 -33
- data/test/damaged_file.edi +1 -0
- data/test/eancom2webedi.rb +1 -0
- data/test/groups.edi +1 -1
- data/test/test_basics.rb +16 -9
- data/test/test_edi_split.rb +30 -0
- data/test/test_loopback.rb +7 -2
- data/test/test_rexml.rb +34 -2
- data/test/test_service_messages.rb +190 -0
- data/test/test_streaming.rb +167 -0
- data/test/test_tut_examples.rb +3 -1
- data/test/webedi2eancom.rb +1 -0
- metadata +121 -77
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 991135e53b123b05465006a77510f27a07315f26
|
4
|
+
data.tar.gz: 3c08cc53d955354fc119c52589a5a86e0a51e6bb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0bc5dd2fec9955e8549b5553280fcbe56066c35a1648299324405be92b96b99598f5da24978e41487be2cd9be95c1e9f67746d0a31cb7a5186a326c1d095c286
|
7
|
+
data.tar.gz: 6a20a3bad4528be17d24ddef2c7e873c3bb45d2e55b327deaed82e51d562b04b5ebcaf47752f5bf7242f1a5743c8116d786fedd0b2e0f5788d4582bf73b5c938
|
data/AuthorCopyright
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
== Author
|
2
2
|
|
3
|
-
Heinz W. Werntges,
|
4
|
-
(edi@
|
3
|
+
Heinz W. Werntges, RheinMain University of Applied Sciences, Wiesbaden
|
4
|
+
(edi-ai-dcsm@hs-rm.de)
|
5
5
|
|
6
6
|
== Copyright
|
7
7
|
|
8
|
-
Copyright (c) 2006 Heinz W. Werntges.
|
8
|
+
Copyright (c) 2006, 2015 Heinz W. Werntges.
|
9
9
|
Licensed under the same terms as Ruby.
|
10
10
|
|
data/{ChangeLog → Changelog}
RENAMED
@@ -1,5 +1,65 @@
|
|
1
1
|
= Change log
|
2
2
|
|
3
|
+
== 0.9.6.2
|
4
|
+
=== Tested with Ruby 2.2.1, some RDoc links fixed
|
5
|
+
|
6
|
+
== 0.9.6.1
|
7
|
+
|
8
|
+
=== Service messages, subset support
|
9
|
+
* Master data for CONTRL, AUTACK and KEYMAN fixed now, new test added
|
10
|
+
* Master data fix: Elimination of non-ASCII chars so Ruby 1.9 does not need -E
|
11
|
+
* Subsets now tolerated (warning & fallback to plain EDIFACT)
|
12
|
+
* More support for subset EANCOM (prepared for master data)
|
13
|
+
|
14
|
+
== 0.9.6.0
|
15
|
+
|
16
|
+
=== Adjustments for Ruby 1.9.2
|
17
|
+
* Encodings added, minor patches required, some typos fixed
|
18
|
+
* Some dead files removed
|
19
|
+
* XML: FPI in doctype declaration adapted to new organization name
|
20
|
+
* Tests: Rakefile replaces Makefile, works for both Ruby 1.8 & 1.9 now
|
21
|
+
|
22
|
+
== 0.9.5.3
|
23
|
+
|
24
|
+
=== Adjustments for Ruby 1.8.7
|
25
|
+
* Changed when cond: ... to when cond then ...
|
26
|
+
* Removed "break" from a case/when block
|
27
|
+
* Corrected expectations in tests for edi_split
|
28
|
+
* Adjusted a test that calls ruby on the cmd line to accept versions (prep for 1.9.x)
|
29
|
+
|
30
|
+
== 0.9.5.2
|
31
|
+
|
32
|
+
=== Misc improvements & bug fixes
|
33
|
+
* Two bugs fixed re. ANSI msg and msg_group initialization
|
34
|
+
* ANSI getters/setters "rXX" in test use now.
|
35
|
+
* Support for 270, 271, 276, 277 added, including test cases
|
36
|
+
|
37
|
+
== 0.9.5.1
|
38
|
+
|
39
|
+
=== News
|
40
|
+
* First limited support for UN/EDIFACT Subsets
|
41
|
+
* Basic support for SEDAS (as source, not target standard)
|
42
|
+
* Basic support for ANSI X12 (just 837, 997 for V4.01)
|
43
|
+
* Support for processing arbitrarily large interchanges through classes
|
44
|
+
EDI::E::StreamingParser and StreamingBuilder
|
45
|
+
* New testcase: test_streaming.rb (large, proprietary testfiles not provided)
|
46
|
+
* peek(): Now featuring ":deep_peek" (group and message structure)
|
47
|
+
* 0.9.5.1: X12 835 supported, test suite: x12 cases added
|
48
|
+
|
49
|
+
=== Changes
|
50
|
+
* Interchange.peek: Now supporting parameters. New: deep_peek
|
51
|
+
* Interchange.parse & Interchange.peek re-implemented based on StreamingBuilder
|
52
|
+
* MsgGroup::E::add() may now prevent auto-validation
|
53
|
+
* Class EDI::Time introduced, base class Time not modified anymore
|
54
|
+
|
55
|
+
=== Misc improvements & bug fixes
|
56
|
+
* EDI::Bzip2Reader::getc() added (needed by new streaming parser)
|
57
|
+
* EDI::Collection::find() added
|
58
|
+
* EDI::Collection::[]: Now accepting also Regex objects
|
59
|
+
* standards.rb: EDIFACT version & release: to_s enforced (bug report by Marius Z., SV1 issue)
|
60
|
+
* 0.9.5.1: EDI::logger available now!
|
61
|
+
|
62
|
+
|
3
63
|
== 0.9.4.1
|
4
64
|
|
5
65
|
=== News
|
data/README
CHANGED
@@ -3,9 +3,10 @@
|
|
3
3
|
This is Ruby gem <b>edi4r</b> version
|
4
4
|
:include:VERSION
|
5
5
|
|
6
|
-
Edi4r was created to greatly simplify the creation and processing of data
|
7
|
-
Electronic Data Interchange (EDI). In particular, it supports the
|
8
|
-
syntax (ISO 9573) and optionally SAP IDocs.
|
6
|
+
Edi4r was created to greatly simplify the creation and processing of data
|
7
|
+
for Electronic Data Interchange (EDI). In particular, it supports the
|
8
|
+
UN/EDIFACT syntax (ISO 9573) and optionally SAP IDocs.
|
9
|
+
Limited support is offered for ANSI X.12 and SEDAS.
|
9
10
|
|
10
11
|
== Installation
|
11
12
|
|
@@ -13,10 +14,14 @@ Install it as any other Ruby gem, e.g.:
|
|
13
14
|
|
14
15
|
sudo gem install edi4r-<version>.gem
|
15
16
|
|
17
|
+
With administrator privileges and network access, just type:
|
18
|
+
|
19
|
+
gem install edi4r
|
20
|
+
|
21
|
+
|
16
22
|
== Usage
|
17
23
|
|
18
|
-
require '
|
19
|
-
require_gem 'edi4r'
|
24
|
+
require 'edi4r' # Older installations: require_gem 'edi4r'
|
20
25
|
require 'edi4r/edifact' # optional
|
21
26
|
|
22
27
|
# Build a UN/EDIFACT interchange from its character representation in a file:
|
@@ -49,15 +54,15 @@ Install it as any other Ruby gem, e.g.:
|
|
49
54
|
|
50
55
|
== See also
|
51
56
|
|
52
|
-
* Background[link:
|
57
|
+
* Background[link:EDI.html] info about data structure and classes.
|
53
58
|
|
54
|
-
* A Tutorial[link:
|
59
|
+
* A Tutorial[link:Tutorial.html] for examples of use.
|
55
60
|
|
56
|
-
* A
|
61
|
+
* A Changelog[link:Changelog.html] is maintained since version 0.8
|
57
62
|
|
58
|
-
* Finally, see TO-DO[link:
|
63
|
+
* Finally, see TO-DO[link:TO-DO.html] for the current wish list.
|
59
64
|
|
60
|
-
* This code is put under the Ruby license, see COPYING[link:
|
65
|
+
* This code is put under the Ruby license, see COPYING[link:COPYING.html] for details.
|
61
66
|
|
62
67
|
:include:AuthorCopyright
|
63
68
|
|
data/Tutorial
CHANGED
@@ -9,7 +9,6 @@
|
|
9
9
|
|
10
10
|
=== Require statements
|
11
11
|
|
12
|
-
require "rubygems"
|
13
12
|
require "edi4r" # Try require_gem if this fails on your site
|
14
13
|
require "edi4r/edifact"
|
15
14
|
require "edi4r-tdid" # Try require_gem if this fails on your site
|
@@ -58,7 +57,7 @@ at any other location. If you need to do that, hold your messages
|
|
58
57
|
in an array, sort them any way you like, and finally add them
|
59
58
|
to the interchange in the desired sequence.
|
60
59
|
|
61
|
-
Note that each
|
60
|
+
Note that each message gets validated by default when you add it to
|
62
61
|
the interchange. If your message needs to be completed only later,
|
63
62
|
you may disable validation by calling:
|
64
63
|
|
@@ -596,7 +595,7 @@ To be supplied later; currently just a room to collect keywords to cover.
|
|
596
595
|
Segments: T-nodes, ordinal number, index, occurrence, max. occurrence
|
597
596
|
empty?, required?
|
598
597
|
|
599
|
-
=== More
|
598
|
+
=== More advanced features
|
600
599
|
|
601
600
|
Validation: warnings and exceptions (logging?)
|
602
601
|
Add-ons to class Time
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.9.
|
1
|
+
0.9.6.2
|
data/bin/edi2xml.rb
CHANGED
@@ -1,17 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
# $Id: edi2xml.rb,v 1.1 2006/08/01 11:20:24 werntges Exp $
|
4
|
-
|
5
|
-
# $Log: edi2xml.rb,v $
|
6
|
-
# Revision 1.1 2006/08/01 11:20:24 werntges
|
7
|
-
# Initial revision
|
8
|
-
#
|
2
|
+
# -*- encoding: ISO-8859-1 -*-
|
9
3
|
#
|
10
|
-
# Author: Heinz W. Werntges (edi@
|
4
|
+
# Author: Heinz W. Werntges (edi@cs.hs-rm.de)
|
11
5
|
#
|
12
6
|
# License: This code is put under the Ruby license
|
13
7
|
#
|
14
|
-
# Copyright (c) 2006 Heinz W. Werntges,
|
8
|
+
# Copyright (c) 2006, 2011 Heinz W. Werntges, Hochschule RheinMain, Wiesbaden
|
15
9
|
#
|
16
10
|
|
17
11
|
# SYNOPSIS:
|
@@ -30,10 +24,12 @@
|
|
30
24
|
#
|
31
25
|
|
32
26
|
require "rubygems"
|
33
|
-
|
34
|
-
|
35
|
-
#
|
27
|
+
require "edi4r"
|
28
|
+
require "edi4r-tdid"
|
29
|
+
#require "edi4r-idoc"
|
36
30
|
require "edi4r/edifact"
|
31
|
+
require "edi4r/ansi_x12"
|
32
|
+
require "edi4r/sedas"
|
37
33
|
require "edi4r/rexml"
|
38
34
|
|
39
35
|
require "getoptlong"
|
@@ -44,7 +40,7 @@ def output( ic )
|
|
44
40
|
fail "DIN 16557 applies only to UN/EDIFACT data" unless ic.syntax=='E'
|
45
41
|
ic.to_din16557_4.write($stdout,0)
|
46
42
|
else
|
47
|
-
ic.to_xml.write($stdout
|
43
|
+
ic.to_xml.write($stdout)
|
48
44
|
end
|
49
45
|
end
|
50
46
|
|
@@ -54,12 +50,12 @@ def usage_and_exit
|
|
54
50
|
Usage:
|
55
51
|
#$0 [-D] [files ...]
|
56
52
|
#$0 [-D] -z edifile.gz [files ...] (Zlib required)
|
57
|
-
#$0 -s E|I [-D] (reads from stdin, E)difact or SAP I)doc)
|
53
|
+
#$0 -s A|E|I [-D] (reads from stdin, A)NSI X12, E)difact or SAP I)doc)
|
58
54
|
Options:
|
59
55
|
-d Activates debug mode by setting $DEBUG=true
|
60
56
|
-D Generate DIN 16557-4 output.
|
61
|
-
-s k Set standard key, k=E for UN/EDIFACT (default) or k=I for SAP IDOC
|
62
|
-
(currently only E supported).
|
57
|
+
-s k Set standard key, k=E for UN/EDIFACT (default), k=A fir ANSI X12, or k=I for SAP IDOC
|
58
|
+
(currently only E and A supported).
|
63
59
|
-z Require Zlib. You may then pass gzipped files directly.
|
64
60
|
Note that Zlib is not always available.
|
65
61
|
EOT
|
data/bin/editool.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# -*- encoding: ISO-8859-1 -*-
|
2
3
|
#
|
3
4
|
# Tool to validate, list and analyze EDI data, based on EDI4R
|
4
5
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# Author: Heinz W. Werntges (edi@informatik.fh-wiesbaden.de)
|
6
|
+
# Author: Heinz W. Werntges (edi@cs.hs-rm.de)
|
8
7
|
#
|
9
8
|
# License: This code is put under the Ruby license
|
10
9
|
#
|
11
|
-
# Copyright (c) 2006 Heinz W. Werntges,
|
10
|
+
# Copyright (c) 2006, 2011 Heinz W. Werntges, RheinMain University of Applied Sciences, Wiesbaden
|
12
11
|
#
|
13
12
|
|
14
13
|
if $DEBUG # Include statement during test setup:
|
@@ -16,7 +15,7 @@ if $DEBUG # Include statement during test setup:
|
|
16
15
|
require 'edi4r'
|
17
16
|
require 'edi4r/edifact'
|
18
17
|
require "edi4r/rexml"
|
19
|
-
|
18
|
+
require "edi4r-tdid"
|
20
19
|
else # Regular include statements:
|
21
20
|
require "rubygems"
|
22
21
|
require "edi4r"
|
@@ -25,6 +24,7 @@ else # Regular include statements:
|
|
25
24
|
rescue LoadError # Ignore error
|
26
25
|
end
|
27
26
|
require "edi4r/edifact"
|
27
|
+
require "edi4r/ansi_x12"
|
28
28
|
require "edi4r/rexml"
|
29
29
|
require "edi4r-tdid"
|
30
30
|
end
|
@@ -63,6 +63,10 @@ def report_peek_result( ic_stub, fname )
|
|
63
63
|
end
|
64
64
|
puts "%15.15s\t%13s\t%13s\t%14s\t%s" % params
|
65
65
|
|
66
|
+
when 'A'
|
67
|
+
params = [fname, h.dI06, h.dI07, h.dI12, h.dI14=='T']
|
68
|
+
puts "%15.15s\t%13s\t%13s\t%14s\t%s" % params
|
69
|
+
|
66
70
|
when 'I'
|
67
71
|
puts "%15.15s\tSAP IDocs not supported yet" % [fname]
|
68
72
|
|
@@ -0,0 +1,1385 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Inter-Standard converter module SEDAS --> EANCOM'02
|
4
|
+
#
|
5
|
+
# Inhouse format: GS1 Germany's SEDAS V5 (April 1993)
|
6
|
+
# Output format: EANCOM'02 INVOIC, according to GS1 Germany'
|
7
|
+
# recommendations for application
|
8
|
+
# (EDI-Anwendungsempfehlungen V 2.0 (INVOIC) in EANCOM 2002 S3)
|
9
|
+
# and the general EANCOM 2002 (INVOIC) documentation
|
10
|
+
# Comments:
|
11
|
+
#
|
12
|
+
# Inhouse and output format were selected, because they represent typical
|
13
|
+
# data structures and tasks for users, and because documentation of
|
14
|
+
# these formats is freely available.
|
15
|
+
#
|
16
|
+
# $Id: sedas2eancom02.rb,v 1.3 2007/04/12 21:54:27 werntges Exp $
|
17
|
+
#
|
18
|
+
# Author: Heinz W. Werntges (edi@informatik.fh-wiesbaden.de)
|
19
|
+
#
|
20
|
+
# License: This code is put under the Ruby license
|
21
|
+
#
|
22
|
+
# Copyright (c) 2007 Heinz W. Werntges, FH Wiesbaden
|
23
|
+
#
|
24
|
+
|
25
|
+
# Include statement during test setup:
|
26
|
+
#if $DEBUG
|
27
|
+
# $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
28
|
+
#else
|
29
|
+
require 'rubygems'
|
30
|
+
#end
|
31
|
+
|
32
|
+
require 'edi4r'
|
33
|
+
require 'edi4r/edifact'
|
34
|
+
require 'edi4r/sedas'
|
35
|
+
require 'logger'
|
36
|
+
|
37
|
+
|
38
|
+
#
|
39
|
+
# Helper methods
|
40
|
+
#
|
41
|
+
# bbbbbbb 00000 c
|
42
|
+
# 1313131 31313 1
|
43
|
+
|
44
|
+
def bbn_to_gln( bbn )
|
45
|
+
bbn = "%07d" % bbn
|
46
|
+
raise "Keine bbn: #{bbn}" unless bbn =~ /\d{7}/
|
47
|
+
gln = bbn + '0' * (13-bbn.length)
|
48
|
+
sum = i = 0
|
49
|
+
gln.split('').reverse_each do |c|
|
50
|
+
sum += c.hex * ((i&1==1) ? 3 : 1)
|
51
|
+
i += 1
|
52
|
+
end
|
53
|
+
sum %= 10
|
54
|
+
return gln if sum==0
|
55
|
+
gln[-1] = ?9+1 - sum
|
56
|
+
gln
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_value( komma_kz, field )
|
60
|
+
case komma_kz # Nr. 4
|
61
|
+
when 0: nil
|
62
|
+
when 1: field.to_i
|
63
|
+
when 2: field.to_i / 10.0
|
64
|
+
when 3: field.to_i / 100.0
|
65
|
+
when 4: field.to_i / 1000.0
|
66
|
+
when 5: field.to_i / 10000.0
|
67
|
+
else raise ArgumentError, "Unzulaessiges Komma-KZ: #{komma_kz}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def qkey_to_qualifier6411( qkey ) # Nr. 5
|
72
|
+
case qkey
|
73
|
+
when nil: nil # not given - don't fill qualifier
|
74
|
+
when 0: nil # empty - should not occur, consider a raise()
|
75
|
+
when 11: nil # PCE
|
76
|
+
when 12: 'KGM'
|
77
|
+
when 13: 'LTR'
|
78
|
+
when 14: 'MTR'
|
79
|
+
when 15: nil # PCE (Anzahl Display/Sortimentseinheiten)
|
80
|
+
when 16: nil # PCE (Anzahl gesamt in den Display/Sortimentseinheiten)
|
81
|
+
# FIXME: 15, 16 nicht spezifiziert - Sonderbehandlung erforderlich?
|
82
|
+
else raise "QTY/PRI: Unbekannter 'Mengenschluessel: '#{qkey}'"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class EDI::E::Message
|
87
|
+
@@curr_year = Time.now.year.to_s # For add_dtm()
|
88
|
+
|
89
|
+
# d2380: Expect Fixnum or String, JMMTT or JJMMTT if d.2379.nil?
|
90
|
+
def add_dtm( data )
|
91
|
+
return nil if data[:d2380].nil? || data[:d2380] =~ /^\s*$/
|
92
|
+
dtm = self.new_segment("DTM")
|
93
|
+
dtm.cC507.d2005 = data[:d2005]
|
94
|
+
if data[:d2379].nil? # Auto-format
|
95
|
+
if data[:digits]==5 # Expected: 5 or 6
|
96
|
+
d = @@curr_year[0,3] + "%05d" % data[:d2380].to_i
|
97
|
+
else
|
98
|
+
d = @@curr_year[0,2] + "%06d" % (data[:d2380].to_i % 1000000)
|
99
|
+
end
|
100
|
+
dtm.cC507.d2380 = d
|
101
|
+
dtm.cC507.d2379 = 102
|
102
|
+
raise ArgumentError, "Datumsformat nicht 102!" if dtm.cC507.d2380.size != 8
|
103
|
+
else # User takes full control
|
104
|
+
dtm.cC507.d2380 = data[:d2380]
|
105
|
+
dtm.cC507.d2379 = data[:d2379]
|
106
|
+
end
|
107
|
+
self.add(dtm)
|
108
|
+
end
|
109
|
+
|
110
|
+
def add_nad( data )
|
111
|
+
return nil if (data[:d3039].nil? || data[:d3039] =~ /^\s*$/) && data[:d3036_1].nil?
|
112
|
+
seg = self.new_segment('NAD')
|
113
|
+
seg.d3035 = data[:d3035]
|
114
|
+
if data[:d3039].nil? || data[:d3039] =~ /^\s*$/
|
115
|
+
seg.cC080.a3036[0].value = data[:d3036_1].strip
|
116
|
+
seg.d3164 = data[:d3164].strip
|
117
|
+
seg.cC059.a3042[0].value = data[:d3042_1].strip
|
118
|
+
seg.d3251 = data[:d3251]
|
119
|
+
else
|
120
|
+
seg.cC082.d3039 = bbn_to_gln(data[:d3039])
|
121
|
+
seg.cC082.d3055 = 9
|
122
|
+
end
|
123
|
+
self.add seg
|
124
|
+
end
|
125
|
+
|
126
|
+
def add_rff( data )
|
127
|
+
return nil if data[:d1154].nil? || data[:d1154] =~ /^\s*$/
|
128
|
+
seg = self.new_segment('RFF')
|
129
|
+
seg.cC506.d1153 = data[:d1153]
|
130
|
+
if data[:d1154].is_a? Fixnum
|
131
|
+
seg.cC506.d1154 = data[:d1154]
|
132
|
+
else
|
133
|
+
seg.cC506.d1154 = data[:d1154].strip
|
134
|
+
end
|
135
|
+
self.add seg
|
136
|
+
end
|
137
|
+
|
138
|
+
def add_tax( data )
|
139
|
+
seg = self.new_segment("TAX")
|
140
|
+
return nil unless data[:ust_kz]
|
141
|
+
case kz=data[:ust_kz]
|
142
|
+
when 0: return nil # skip!
|
143
|
+
when 1,6: seg.cC243.d5278, seg.d5305 = 0, 'E' # 0%
|
144
|
+
when 2,7: seg.cC243.d5278, seg.d5305 = 7, 'S' # 7%
|
145
|
+
when 3: seg.cC243.d5278, seg.d5305 = 19, 'S' # 19%
|
146
|
+
when 8: seg.cC243.d5278, seg.d5305 = 16, 'S' # 16%
|
147
|
+
$log.warn("add_tax: USt-Kz 8! pos_nr=#{data[:pos_nr]}")
|
148
|
+
else raise "TAX: Unbekanntes Umsatzsteuer-Kennzeichen: '#{kz}' (pos_nr=#{data[:pos_nr]})"
|
149
|
+
end
|
150
|
+
seg.cC241.d5153= 'VAT'
|
151
|
+
seg.d5283 = 7
|
152
|
+
self.add seg
|
153
|
+
end
|
154
|
+
|
155
|
+
def add_pat( data )
|
156
|
+
seg = self.new_segment("PAT")
|
157
|
+
seg.d4279 = data[:d4279]
|
158
|
+
seg.cC112.d2475 = data[:d2475]
|
159
|
+
seg.cC112.d2009 = data[:d2009]
|
160
|
+
seg.cC112.d2151 = data[:d2151]
|
161
|
+
seg.cC112.d2152 = data[:d2152]
|
162
|
+
self.add seg
|
163
|
+
end
|
164
|
+
|
165
|
+
def add_alc( data )
|
166
|
+
seg = self.new_segment("ALC")
|
167
|
+
seg.d5463 = data[:d5463] || 'A'
|
168
|
+
seg.cC214.d7161 = data[:d7161] || 'DI'
|
169
|
+
seg.d1227 = data[:d1227]
|
170
|
+
self.add seg
|
171
|
+
end
|
172
|
+
|
173
|
+
def add_lin( data )
|
174
|
+
seg = self.new_segment("LIN")
|
175
|
+
return nil if data[:d7140].nil?
|
176
|
+
seg.d1082 = data[:d1082]
|
177
|
+
seg.cC212.d7140 = bbn_to_gln( data[:d7140] )
|
178
|
+
seg.cC212.d7143 = data[:d7143] || 'SRV'
|
179
|
+
if data[:c829_d1082]
|
180
|
+
seg.cC829.d5495 = data[:c829_d5495] || 1
|
181
|
+
seg.cC829.d1082 = data[:c829_d1082]
|
182
|
+
end
|
183
|
+
self.add seg
|
184
|
+
end
|
185
|
+
|
186
|
+
def add_pia( data )
|
187
|
+
seg = self.new_segment("PIA")
|
188
|
+
return nil if data[:d4347].nil?
|
189
|
+
seg.d4347 = data[:d4347] # e.g., 1
|
190
|
+
cde = seg.aC212[0]
|
191
|
+
cde.d7140 =
|
192
|
+
data[:d7140].respond_to?(:strip) ? data[:d7140].strip : data[:d7140]
|
193
|
+
cde.d7143 = data[:d7143]
|
194
|
+
cde.d3055 = data[:d3055]
|
195
|
+
self.add seg
|
196
|
+
end
|
197
|
+
|
198
|
+
def add_imd( data )
|
199
|
+
seg = self.new_segment("IMD")
|
200
|
+
return nil if data[:d7077].nil?
|
201
|
+
seg.d7077 = data[:d7077]
|
202
|
+
seg.cC272.d7081 = data[:d7081]
|
203
|
+
seg.cC272.d3055 = data[:d7081_3055]
|
204
|
+
seg.cC273.d7009 = data[:d7009]
|
205
|
+
seg.cC273.d3055 = data[:d7009_3055]
|
206
|
+
seg.cC273.a7008[0].value =
|
207
|
+
data[:d7008_1].respond_to?(:strip) ? data[:d7008_1].strip : data[:d7008_1]
|
208
|
+
self.add seg
|
209
|
+
end
|
210
|
+
|
211
|
+
def add_qty( data )
|
212
|
+
seg = self.new_segment("QTY")
|
213
|
+
return nil if data[:qkey]==0
|
214
|
+
seg.cC186.d6411 = qkey_to_qualifier6411( data[:qkey] )
|
215
|
+
seg.cC186.d6063 = data[:d6063]
|
216
|
+
seg.cC186.d6060 = data[:d6060]
|
217
|
+
self.add seg
|
218
|
+
end
|
219
|
+
|
220
|
+
def add_pri( data )
|
221
|
+
seg = self.new_segment("PRI")
|
222
|
+
case data[:pkey]
|
223
|
+
when nil: return nil # FIXME: Check! / Don't use this DE
|
224
|
+
when 0, 9: return nil # empty or w/o charge
|
225
|
+
when 1:
|
226
|
+
when 2: seg.cC509.d5284 = 100
|
227
|
+
when 3: seg.cC509.d5284 = 1000
|
228
|
+
else raise "PRI: Unbekannter 'Preisschluessel: '#{data[:pkey]}'"
|
229
|
+
end
|
230
|
+
seg.cC509.d5125 = data[:d5125]
|
231
|
+
seg.cC509.d6411 = qkey_to_qualifier6411( data[:qkey] )
|
232
|
+
seg.cC509.d5118 = data[:d5118]
|
233
|
+
self.add seg
|
234
|
+
end
|
235
|
+
|
236
|
+
def add_moa( data )
|
237
|
+
seg = self.new_segment("MOA")
|
238
|
+
seg.cC516.d5025 = data[:d5025]
|
239
|
+
seg.cC516.d5004 = data[:d5004]
|
240
|
+
self.add seg
|
241
|
+
end
|
242
|
+
|
243
|
+
def add_pcd( data )
|
244
|
+
seg = self.new_segment("PCD")
|
245
|
+
seg.cC501.d5245 = data[:d5245]
|
246
|
+
seg.cC501.d5482 = data[:d5482]
|
247
|
+
self.add seg
|
248
|
+
end
|
249
|
+
|
250
|
+
def add_rte( data )
|
251
|
+
seg = self.new_segment("RTE")
|
252
|
+
seg.cC128.d5419 = data[:d5419]
|
253
|
+
seg.cC128.d5420 = data[:d5420]
|
254
|
+
self.add seg
|
255
|
+
end
|
256
|
+
|
257
|
+
end
|
258
|
+
|
259
|
+
|
260
|
+
Verkettung01_Felder = Struct.new(:v_nad_by, :v_nad_ds,
|
261
|
+
:v_nad_su_va, :v_nad_su_fc, :v_nad_by_va,
|
262
|
+
:ls_a_kz, :ls_a_nr1, :ls_a_nr2)
|
263
|
+
|
264
|
+
Verkettung02_Felder = Struct.new(:empty, :ust_prozentsatz,
|
265
|
+
:preisschluessel, :komma_kz_p, :grundpreis,
|
266
|
+
:mengenschluessel, :komma_kz_m, :menge)
|
267
|
+
|
268
|
+
|
269
|
+
class SEDAS_to_EANCOM02_Map_INVOIC
|
270
|
+
include EDI
|
271
|
+
|
272
|
+
attr_accessor :with_ung
|
273
|
+
|
274
|
+
|
275
|
+
def map_00_to_unb( s00 )
|
276
|
+
unb = @ic.header
|
277
|
+
unb.cS002.d0004 = bbn_to_gln( s00.bbn_absender_dt )
|
278
|
+
unb.cS002.d0007 = 14
|
279
|
+
unb.cS003.d0010 = bbn_to_gln( s00.bbn_empfaenger_dt )
|
280
|
+
unb.cS003.d0007 = 14
|
281
|
+
unb.cS004.d0017 = s00.datum_erstellung
|
282
|
+
unb.cS004.d0019 = '0000'
|
283
|
+
unb.d0035 = 1 if s00.dateistatus =~ /[KT]/
|
284
|
+
unb.cS005.d0022 = s00.datei_archiv_nr.strip
|
285
|
+
unb.d0020 = s00.lfd_nr_dt_empfaenger
|
286
|
+
$ung_0048 = {} # Reset store for uniqueness check of UNG ref numbers
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
def map_01_to_ung( s01 )
|
291
|
+
grp = @ic.new_msggroup( @msg_params )
|
292
|
+
ung = grp.header
|
293
|
+
ung.cS006.d0040 = bbn_to_gln( s01.bbn_absender )
|
294
|
+
ung.cS006.d0007 = 14
|
295
|
+
ung.cS007.d0044 = bbn_to_gln( s01.bbn_empfaenger )
|
296
|
+
ung.cS007.d0007 = 14
|
297
|
+
ung.cS004.d0017 = s01.datum_erstellung
|
298
|
+
ung.cS004.d0019 = '0000'
|
299
|
+
log_nr = s01.log_nr
|
300
|
+
warn "SA01: Log-Nr. #{log_nr} bereits verwendet!" if $ung_0048[log_nr]
|
301
|
+
ung.d0048 = log_nr
|
302
|
+
$ung_0048[log_nr]=true
|
303
|
+
@ic.add grp
|
304
|
+
@p = grp
|
305
|
+
end
|
306
|
+
|
307
|
+
|
308
|
+
def map_12_to_325( s_msg, master_data )
|
309
|
+
@msg = @p.new_message( @msg_params )
|
310
|
+
item_counter = 1
|
311
|
+
|
312
|
+
# Lookahead / out-of-sequence segments first:
|
313
|
+
#
|
314
|
+
ftx_in_header = []
|
315
|
+
# 08 for SA 12/22, 15/25
|
316
|
+
s_msg[/[12][25]08/].each do |seg|
|
317
|
+
ftx = @msg.new_segment("FTX")
|
318
|
+
ftx.d4451 = 'ZZZ'
|
319
|
+
ftx.cC108.a4440[0].value = seg.freitext.strip
|
320
|
+
ftx.d3453 = 'DE'
|
321
|
+
ftx_in_header << ftx
|
322
|
+
end
|
323
|
+
# 08 for SA 14/24, 17/27
|
324
|
+
s_msg[/[12][47]08/].each do |seg|
|
325
|
+
ftx = @msg.new_segment("FTX")
|
326
|
+
ftx.d4451 = 'SUR'
|
327
|
+
ftx.cC108.a4440[0].value = seg.freitext.strip
|
328
|
+
ftx.d3453 = 'DE'
|
329
|
+
ftx_in_header << ftx
|
330
|
+
end
|
331
|
+
|
332
|
+
s01 = Verkettung01_Felder.new
|
333
|
+
if seg=s_msg[/[12][25]01/].first # 1201, 2201, 1501, 2501
|
334
|
+
s01.v_nad_by = seg.bbn_rechnungsempfaenger
|
335
|
+
s01.v_nad_ds = seg.bbn_warenlieferant
|
336
|
+
s01.v_nad_su_va = seg.ust_ident_nr_lieferant
|
337
|
+
s01.v_nad_su_fc = seg.steuer_nr
|
338
|
+
s01.v_nad_by_va = seg.ust_ident_nr_erwerber
|
339
|
+
s01.ls_a_kz = seg.ls_auftrag_kz
|
340
|
+
s01.ls_a_nr1 = seg.ls_auftrag_nr_1
|
341
|
+
s01.ls_a_nr2 = seg.ls_auftrag_nr_2
|
342
|
+
else
|
343
|
+
s01.ls_a_kz = 0
|
344
|
+
end
|
345
|
+
|
346
|
+
# Naming convention:
|
347
|
+
#
|
348
|
+
# shd = SEDAS header record, e.g. a SA12/22 or a SA15/25
|
349
|
+
# str = SEDAS trailer record, e.g. a SA14/24 or a SA17/27
|
350
|
+
#
|
351
|
+
shd = s_msg[/[12][25]00/].first # Must exist due to SEDAS msg definition!
|
352
|
+
all_str = s_msg[/[12][47]00/] # Expect one per VAT rate, one at least
|
353
|
+
|
354
|
+
ls_auftrag_array = [[shd.ls_auftrag_kz_1, shd.ls_auftrag_nr_1, 1],
|
355
|
+
[shd.ls_auftrag_kz_2, shd.ls_auftrag_nr_2, 2],
|
356
|
+
[shd.ls_auftrag_kz_3, shd.ls_auftrag_nr_3, 3],
|
357
|
+
[shd.ls_auftrag_kz_4, shd.ls_auftrag_nr_4, 4],
|
358
|
+
[shd.ls_auftrag_kz_5, shd.ls_auftrag_nr_5, 5]]
|
359
|
+
|
360
|
+
summe_131 = 0 # Evtl. erst Skonto addieren, siehe ALC (EAB)
|
361
|
+
|
362
|
+
# BGM
|
363
|
+
#
|
364
|
+
bgm = @msg.new_segment("BGM")
|
365
|
+
bgm.cC002.d1001 = 325
|
366
|
+
bgm.cC106.d1004 = shd.beleg_nr
|
367
|
+
bgm.d1225 = 9
|
368
|
+
@msg.add(bgm)
|
369
|
+
|
370
|
+
# All DTM
|
371
|
+
#
|
372
|
+
@msg.add_dtm(:d2005=> 137, :digits=> 5, :d2380=>shd.datum_liefernachweis)
|
373
|
+
@msg.add_dtm(:d2005=> 35, :d2380=> shd.lieferdatum)
|
374
|
+
[
|
375
|
+
[shd.ls_auftrag_kz, shd.ls_auftrag_nr, shd.auftrags_nr_besteller, 1],
|
376
|
+
[s01.ls_a_kz, s01.ls_a_nr1, s01.ls_a_nr2, 2]
|
377
|
+
].each do |a|
|
378
|
+
kz, nr1, nr2, no = a
|
379
|
+
next unless kz==2 # Lieferdatum von-bis (0JJMMTT)
|
380
|
+
dt = if nr1.is_a? String
|
381
|
+
@curr_year[0,2]+nr1[1,6]+@curr_year[0,2]+nr2[1,6]
|
382
|
+
else
|
383
|
+
@curr_year[0,2]+"%06d" % nr1 + @curr_year[0,2]+"%06d" % nr2
|
384
|
+
end
|
385
|
+
@msg.add_dtm( :d2005=>35, :d2380=>dt, :d2379=>718 ) # CCYYMMDD-CCYYMMDD
|
386
|
+
end
|
387
|
+
|
388
|
+
# All FTX
|
389
|
+
#
|
390
|
+
ftx_in_header.each {|obj| @msg.add(obj)}
|
391
|
+
|
392
|
+
# SG1: RFF-DTM
|
393
|
+
#
|
394
|
+
case q=shd.s_rechnung_kz # Nr. 2, Anmerkung 2
|
395
|
+
when 0 # empty - skip
|
396
|
+
when 6,8
|
397
|
+
@msg.add_rff( :d1153=>'IV', :d1154=> shd.s_rechnung_nr )
|
398
|
+
@msg.add_dtm( :d2005=> 171, :d2380=> shd.datum_s_beleg )
|
399
|
+
when 7,9
|
400
|
+
@msg.add_rff( :d1153=>'IV', :d1154=> shd.s_rechnung_nr )
|
401
|
+
else
|
402
|
+
raise "Kennzeichen S.-Rechnung: ungueltig: #{q}"
|
403
|
+
end
|
404
|
+
|
405
|
+
[
|
406
|
+
[shd.ls_auftrag_kz, shd.ls_auftrag_nr, shd.auftrags_nr_besteller, 1],
|
407
|
+
[s01.ls_a_kz, s01.ls_a_nr1, s01.ls_a_nr2, 2]
|
408
|
+
].each do |a|
|
409
|
+
kz, nr1, nr2, no = a
|
410
|
+
case kz # Nr. 3, Anmerkung 1
|
411
|
+
when nil # treat as empty, should not occur
|
412
|
+
$log.warn("ls_auftrag_kz (#{no}) fehlt!")
|
413
|
+
when 0 # empty - skip
|
414
|
+
when 1
|
415
|
+
@msg.add_rff( :d1153=>'DQ', :d1154=> nr1 )
|
416
|
+
@msg.add_rff( :d1153=>'ON', :d1154=> nr2 )
|
417
|
+
when 2 # skip - treated earlier (DTM)
|
418
|
+
when 3
|
419
|
+
@msg.add_rff( :d1153=>'ON', :d1154=> nr1 )
|
420
|
+
when 4
|
421
|
+
@msg.add_rff( :d1153=>'DQ', :d1154=> nr1 )
|
422
|
+
else
|
423
|
+
raise "Kennzeichen LS/Auftrag (#{no}) ungueltig (Anm. 1): '#{kz}'"
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
ls_auftrag_array.each do |a|
|
428
|
+
kz, nr1, no = a
|
429
|
+
case kz # Nr. 3, Anmerkung 3
|
430
|
+
when 0 # empty - skip
|
431
|
+
when 5 # Lieferscheinnummer
|
432
|
+
@msg.add_rff( :d1153=>'DQ', :d1154=> nr1 )
|
433
|
+
when 6 # Auftragsnummer
|
434
|
+
@msg.add_rff( :d1153=>'ON', :d1154=> nr1 )
|
435
|
+
else
|
436
|
+
raise "Kennzeichen LS/Auftrag (#{no}) ungueltig (Anm. 3): '#{kz}'"
|
437
|
+
end
|
438
|
+
end # each
|
439
|
+
|
440
|
+
# SG2: NAD-RFF
|
441
|
+
#
|
442
|
+
@msg.add_nad( :d3035=>'SU', :d3039=> shd.bbn_lieferant )
|
443
|
+
@msg.add_rff( :d1153=>'VA', :d1154=> s01.v_nad_su_va )
|
444
|
+
@msg.add_rff( :d1153=>'FC', :d1154=> s01.v_nad_su_fc )
|
445
|
+
|
446
|
+
bbn = s01.v_nad_by
|
447
|
+
bbn = shd.bbn_rechnungsempfaenger if bbn.nil? || bbn == 0
|
448
|
+
@msg.add_nad( :d3035=>'BY', :d3039=> bbn )
|
449
|
+
@msg.add_rff( :d1153=>'VA', :d1154=> s01.v_nad_by_va )
|
450
|
+
|
451
|
+
case kz=shd.warenempfaenger_kz
|
452
|
+
when 1
|
453
|
+
bbn = shd.bbn_warenempfaenger.to_s + "%06d" % shd.interne_nr
|
454
|
+
@msg.add_nad( :d3035=>'DP', :d3039=> bbn )
|
455
|
+
when 2
|
456
|
+
s51 = master_data['51'].find{|s| s.refpos_nr == shd.positions_nr}
|
457
|
+
raise "Sorry - SA51 fehlt fuer pos_nr={shd.positions_nr}" unless s51
|
458
|
+
@msg.add_nad( :d3035=>'DP', :d3036_1=> s51.name_warenempfaenger,
|
459
|
+
:d3164=> s51.ort,
|
460
|
+
:d3042_1=> s51.strasse_postfach,
|
461
|
+
:d3251=> s51.plz_1==0 ? s51.plz_2.strip : s51.plz_1 )
|
462
|
+
# @msg.add_rff( :d1153=>'IA', :d1154=> shd.interne_nr )
|
463
|
+
when 3
|
464
|
+
bbn = shd.bbn_warenempfaenger
|
465
|
+
@msg.add_nad( :d3035=>'DP', :d3039=> bbn )
|
466
|
+
else
|
467
|
+
raise "Warenempfaenger-bbs: 'Kennzeichen' ungueltig: '#{kz}'"
|
468
|
+
end
|
469
|
+
|
470
|
+
# TAX-MOA SG6
|
471
|
+
#
|
472
|
+
all_str.each {|s| @msg.add_tax( :ust_kz=> s.ust_kz, :pos_nr=> s.positions_nr ) }
|
473
|
+
|
474
|
+
# ALC-MOA SG16
|
475
|
+
#
|
476
|
+
all_str.each do |s|
|
477
|
+
kz, betrag = s.fracht_verpackung_kz, s.fracht_verpackung
|
478
|
+
next if kz == 0
|
479
|
+
params = {}
|
480
|
+
params[:d5463] = betrag > 0 ? 'C' : 'A'
|
481
|
+
params[:d7161] = case kz
|
482
|
+
when 1: 'FC'
|
483
|
+
when 2: 'PC'
|
484
|
+
when 3: 'IN'
|
485
|
+
when 4,5,6,7: 'SH'
|
486
|
+
else raise "'Fracht/Verpackungs-Kennzeichen' ungueltig: '#{kz}'"
|
487
|
+
end
|
488
|
+
@msg.add_alc( params )
|
489
|
+
@msg.add_moa( :d5025=> 8, :d5004=> betrag.abs/100.0 )
|
490
|
+
end
|
491
|
+
|
492
|
+
all_str.each do |s|
|
493
|
+
betrag = s.skonto
|
494
|
+
next if betrag == 0
|
495
|
+
@msg.add_alc( :d5463=> 'A', :d1227=> 1, :d7161=> 'EAB' )
|
496
|
+
@msg.add_moa( :d5025=> 8, :d5004=> betrag.abs/100.0 )
|
497
|
+
summe_131 += betrag
|
498
|
+
warn "Skonto positiv: #{s.skonto}, pos_nr=#{s.positions_nr}" if betrag>0
|
499
|
+
end
|
500
|
+
|
501
|
+
all_str.each do |s| # Also see code at item level, SG39
|
502
|
+
[[s.rabatt_kz_1, s.nachweisrabatt_1, 1],
|
503
|
+
[s.rabatt_kz_2, s.nachweisrabatt_2, 2],
|
504
|
+
[s.rabatt_kz_3, s.nachweisrabatt_3, 3],
|
505
|
+
[s.rabatt_kz_4, s.nachweisrabatt_4, 4]].each do |a|
|
506
|
+
kz, betrag, no = a
|
507
|
+
next if kz == 0
|
508
|
+
|
509
|
+
params = {
|
510
|
+
:d5463=> betrag < 0 ? 'A' : 'C',
|
511
|
+
:d7161=> 'DI', :d1227=> kz%10 - 1
|
512
|
+
}
|
513
|
+
params[:d1227] = nil unless params[:d1227].between?(1,4)
|
514
|
+
@msg.add_alc( params )
|
515
|
+
|
516
|
+
case (kz - kz%10)/10
|
517
|
+
when 1..4, 6
|
518
|
+
@msg.add_moa( :d5025=> 8, :d5004=> betrag.abs/100.0 )
|
519
|
+
when 5
|
520
|
+
@msg.add_moa( :d5025=> 8, :d5004=> betrag.abs/100.0 )
|
521
|
+
pri_aab.d5125 = 'AAA' if pri_aab # Why?
|
522
|
+
when 7
|
523
|
+
@msg.add_pcd( :d5245=> 3, :d5482=> betrag.abs/10000.0 )
|
524
|
+
when 8
|
525
|
+
@msg.add_rte( :d5419=> 1, :d5420=> betrag.abs/10000.0 )
|
526
|
+
else
|
527
|
+
raise "ALC: Unbekanntes 'Rabatt-Kennzeichen: '#{kz}'"
|
528
|
+
end
|
529
|
+
end
|
530
|
+
end
|
531
|
+
|
532
|
+
# Items: Map elsewhere
|
533
|
+
#
|
534
|
+
s_msg[/[12][36]00/].each do |s|
|
535
|
+
map_12_to_325_item( s.descendants_and_self, item_counter, master_data )
|
536
|
+
item_counter += 2
|
537
|
+
end
|
538
|
+
|
539
|
+
# Trailer
|
540
|
+
#
|
541
|
+
uns = @msg.new_segment("UNS")
|
542
|
+
uns.d0081 = 'S'
|
543
|
+
@msg.add(uns)
|
544
|
+
|
545
|
+
# MOA SG50
|
546
|
+
#
|
547
|
+
summe_402, summe_79, summe_77 = 0,0.0, 0
|
548
|
+
# summe_131: siehe oben
|
549
|
+
all_str.each do |s|
|
550
|
+
if s.b_vereinbarung_kz_1 == 2 # Nr. 24
|
551
|
+
summe_402 += s.b_vereinbarung_1
|
552
|
+
end
|
553
|
+
summe_131 += s.nachweisrabatt_gesamt
|
554
|
+
summe_77 += s.nachweis_endbetrag
|
555
|
+
if s.warenwert_kz == 1 # Nr. 11: 1=Warenwert
|
556
|
+
summe_79 += to_value( s.komma_kz, s.warenbetrag_menge )
|
557
|
+
end
|
558
|
+
end
|
559
|
+
@msg.add_moa( :d5025=> 402, :d5004=> summe_402/100.0 ) if summe_402 != 0
|
560
|
+
@msg.add_moa( :d5025=> 131, :d5004=> summe_131/100.0 ) if summe_131 != 0
|
561
|
+
@msg.add_moa( :d5025=> 79, :d5004=> summe_79 )
|
562
|
+
@msg.add_moa( :d5025=> 77, :d5004=> summe_77 /100.0 ) if summe_77 != 0
|
563
|
+
|
564
|
+
# TAX-MOA SG52, only if more than 1 STR record found
|
565
|
+
#
|
566
|
+
all_str.each do |s|
|
567
|
+
@msg.add_tax( :ust_kz=> s.ust_kz, :pos_nr=> s.positions_nr )
|
568
|
+
if s.warenwert_kz == 1 # Nr. 11: 1=Warenwert
|
569
|
+
@msg.add_moa( :d5025=> 79, :d5004=> s.warenbetrag_menge/100.0 )
|
570
|
+
end
|
571
|
+
betrag = s.nachweisrabatt_gesamt + s.skonto
|
572
|
+
@msg.add_moa( :d5025=> 131, :d5004=> betrag/100.0 ) if betrag != 0
|
573
|
+
end if all_str.size > 1
|
574
|
+
|
575
|
+
@p.add @msg, false
|
576
|
+
end
|
577
|
+
|
578
|
+
|
579
|
+
def map_12_to_325_item( segments, item_counter, master_data )
|
580
|
+
# Lookahead / out-of-sequence segments first:
|
581
|
+
ftx_in_item = []
|
582
|
+
segments.find_all{|seg| seg.name=~/[12][36]08/}.each do |seg|
|
583
|
+
ftx = @msg.new_segment("FTX")
|
584
|
+
ftx.d4451 = 'ZZZ'
|
585
|
+
ftx.cC108.a4440[0].value = seg.freitext.strip
|
586
|
+
ftx.d3453 = 'DE'
|
587
|
+
ftx_in_item << ftx
|
588
|
+
end
|
589
|
+
|
590
|
+
s02 = Verkettung02_Felder.new
|
591
|
+
if seg=segments.find{|s| s.name=~/[12][36]02/} # just 0..1 expected
|
592
|
+
s02.ust_prozentsatz = seg.ust_prozentsatz
|
593
|
+
s02.preisschluessel = seg.preisschluessel
|
594
|
+
s02.komma_kz_p = seg.komma_kz_p
|
595
|
+
s02.grundpreis = seg.grundpreis
|
596
|
+
s02.mengenschluessel = seg.mengenschluessel
|
597
|
+
s02.komma_kz_m = seg.komma_kz_m
|
598
|
+
s02.menge = seg.menge
|
599
|
+
s02.empty = false
|
600
|
+
else
|
601
|
+
s02.empty = true
|
602
|
+
end
|
603
|
+
|
604
|
+
# Now do the serial mapping
|
605
|
+
segments.each do |seg|
|
606
|
+
|
607
|
+
seg_id = seg.name
|
608
|
+
seg_id += ' ' + seg.sg_name if seg.sg_name
|
609
|
+
case seg_id
|
610
|
+
when /[12][36]00 SG1/
|
611
|
+
# FIXME: Linear search - consider a hash for fast lookup via ean.
|
612
|
+
s5000 = master_data.find{|s| s.name=='5000' && s.ean==seg.ean}
|
613
|
+
raise "SA 50 fehlt fuer EAN #{seg.ean}, pos_nr=#{seg.positions_nr}" unless s5000
|
614
|
+
|
615
|
+
@msg.add_lin( :d1082=> item_counter, :d7140=> seg.ean)
|
616
|
+
|
617
|
+
# PIA
|
618
|
+
#
|
619
|
+
@msg.add_pia( :d4347=> 1, :d7140=> s5000.artikel_nr, :d7143=> 'SA')
|
620
|
+
|
621
|
+
# IMD
|
622
|
+
#
|
623
|
+
@msg.add_imd( :d7077=> 'C', :d7009=> 'IN', :d7009_3055=> 9)
|
624
|
+
@msg.add_imd( :d7077=> 'A', :d7008_1=> s5000.langtext)
|
625
|
+
|
626
|
+
# QTY
|
627
|
+
#
|
628
|
+
if s02.empty || s02.mengenschluessel == 0 || s02.komma_kz_m == 0
|
629
|
+
mengenschluessel, komma_kz_m, menge =
|
630
|
+
seg.mengenschluessel, seg.komma_kz_m, seg.menge
|
631
|
+
else
|
632
|
+
mengenschluessel, komma_kz_m, menge =
|
633
|
+
s02.mengenschluessel, s02.komma_kz_m, s02.menge
|
634
|
+
end
|
635
|
+
if s02.empty || s02.preisschluessel == 0 || s02.komma_kz_p == 0
|
636
|
+
preisschluessel, komma_kz_p, grundpreis =
|
637
|
+
seg.preisschluessel, seg.komma_kz_p, seg.grundpreis
|
638
|
+
else
|
639
|
+
preisschluessel, komma_kz_p, grundpreis =
|
640
|
+
s02.preisschluessel, s02.komma_kz_p, s02.grundpreis
|
641
|
+
end
|
642
|
+
@msg.add_qty( :d6063=> preisschluessel == 9 ? 192 : 47, # w/o charge?
|
643
|
+
:d6060=> to_value( komma_kz_m, menge ),
|
644
|
+
:qkey=> mengenschluessel )
|
645
|
+
|
646
|
+
# All FTX
|
647
|
+
#
|
648
|
+
ftx_in_item.each {|obj| @msg.add(obj)}
|
649
|
+
|
650
|
+
# MOA
|
651
|
+
#
|
652
|
+
betrag = seg.artikelrabatt_gesamt
|
653
|
+
@msg.add_moa( :d5025=> 131, :d5004=> betrag/100.0 ) if betrag != 0
|
654
|
+
betrag = seg.warenwert
|
655
|
+
@msg.add_moa( :d5025=> 203, :d5004=> betrag/100.0 ) if betrag != 0
|
656
|
+
if seg.b_vereinbarung_kz_2 == 3
|
657
|
+
@msg.add_moa( :d5025=> 204, :d5004=> seg.b_vereinbarung_2/10.0 )
|
658
|
+
end
|
659
|
+
|
660
|
+
# PRI
|
661
|
+
#
|
662
|
+
pri_aab =
|
663
|
+
@msg.add_pri(:d5125=>'AAB', :d5118=>to_value( komma_kz_p,grundpreis),
|
664
|
+
:pkey=>preisschluessel, :qkey=>mengenschluessel )
|
665
|
+
if seg.schluessel_kz == 1
|
666
|
+
@msg.add_pri( :d5125=>'AAE',
|
667
|
+
:d5118=>to_value( seg.komma_kz, seg.sondereintrag ) )
|
668
|
+
# :pkey=>preisschluessel, :qkey=>mengenschluessel)
|
669
|
+
elsif seg.schluessel_kz == 3
|
670
|
+
@msg.add_pri( :d5125=>'AAA',
|
671
|
+
:d5118=>to_value( seg.komma_kz, seg.sondereintrag ) )
|
672
|
+
end
|
673
|
+
|
674
|
+
# RFF-DTM SG30
|
675
|
+
#
|
676
|
+
if seg.b_vereinbarung_kz_2 == 5
|
677
|
+
@msg.add_rff( :d1153=>'AAK', :d1154=> seg.b_vereinbarung_2 )
|
678
|
+
end
|
679
|
+
|
680
|
+
# TAX-MOA
|
681
|
+
#
|
682
|
+
@msg.add_tax( :ust_kz=> seg.umsatzsteuer_kz, :pos_nr=> seg.positions_nr )
|
683
|
+
|
684
|
+
|
685
|
+
# ALC SG39
|
686
|
+
#
|
687
|
+
[[seg.rabatt_kz_1, seg.artikelrabatt_1, 1],
|
688
|
+
[seg.rabatt_kz_2, seg.artikelrabatt_2, 2],
|
689
|
+
[seg.rabatt_kz_3, seg.artikelrabatt_3, 3],
|
690
|
+
[seg.rabatt_kz_4, seg.artikelrabatt_4, 4]].each do |a|
|
691
|
+
kz, betrag, no = a
|
692
|
+
next if kz == 0
|
693
|
+
|
694
|
+
params = {
|
695
|
+
:d5463=> betrag < 0 ? 'A' : 'C',
|
696
|
+
:d7161=> 'DI', :d1227=> kz%10 - 1
|
697
|
+
}
|
698
|
+
params[:d1227] = nil unless params[:d1227].between?(1,4)
|
699
|
+
@msg.add_alc( params )
|
700
|
+
|
701
|
+
case (kz - kz%10)/10
|
702
|
+
when 1..4, 6
|
703
|
+
@msg.add_moa( :d5025=> 8, :d5004=> betrag.abs/100.0 )
|
704
|
+
when 5
|
705
|
+
@msg.add_moa( :d5025=> 8, :d5004=> betrag.abs/100.0 )
|
706
|
+
pri_aab.d5125 = 'AAA' if pri_aab # Why?
|
707
|
+
when 7
|
708
|
+
@msg.add_pcd( :d5245=> 3, :d5482=> betrag.abs/10000.0 )
|
709
|
+
when 8
|
710
|
+
@msg.add_rte( :d5419=> 1, :d5420=> betrag.abs/10000.0 )
|
711
|
+
else
|
712
|
+
raise "ALC: Unbekanntes 'Rabatt-Kennzeichen: '#{kz}'"
|
713
|
+
end
|
714
|
+
end
|
715
|
+
|
716
|
+
# Sub-line info
|
717
|
+
#
|
718
|
+
@msg.add_lin( :d1082=> item_counter+1,
|
719
|
+
:d7140=> s5000.kleinste_ean,
|
720
|
+
:c829_d1082 => item_counter )
|
721
|
+
|
722
|
+
@msg.add_pia( :d4347=> 1, :d7140=> "%04d" % s5000.klassifikation,
|
723
|
+
:d7143=> 'GN')
|
724
|
+
@msg.add_imd( :d7077=> 'C', :d7009=> 'CU', :d7009_3055=> 9)
|
725
|
+
@msg.add_qty( :d6063=> 59, :d6060=> s5000.menge_ean )
|
726
|
+
|
727
|
+
|
728
|
+
when /[12][36]0[28] SG1/
|
729
|
+
# ignored here - handled by lookahead section
|
730
|
+
|
731
|
+
else
|
732
|
+
raise "Segment-Id #{seg_id} hier nicht erwartet!"
|
733
|
+
end
|
734
|
+
end
|
735
|
+
end
|
736
|
+
|
737
|
+
|
738
|
+
def map_15_to_38x( s_msg, master_data )
|
739
|
+
@msg = @p.new_message( @msg_params )
|
740
|
+
item_counter = 1
|
741
|
+
|
742
|
+
# Lookahead / out-of-sequence segments first:
|
743
|
+
#
|
744
|
+
ftx_in_header = []
|
745
|
+
# 08 for SA 12/22, 15/25
|
746
|
+
s_msg[/[12][25]08/].each do |seg|
|
747
|
+
ftx = @msg.new_segment("FTX")
|
748
|
+
ftx.d4451 = 'ZZZ'
|
749
|
+
ftx.cC108.a4440[0].value = seg.freitext.strip
|
750
|
+
ftx.d3453 = 'DE'
|
751
|
+
ftx_in_header << ftx
|
752
|
+
end
|
753
|
+
# 08 for SA 14/24, 17/27
|
754
|
+
s_msg[/[12][47]08/].each do |seg|
|
755
|
+
ftx = @msg.new_segment("FTX")
|
756
|
+
ftx.d4451 = 'SUR'
|
757
|
+
ftx.cC108.a4440[0].value = seg.freitext.strip
|
758
|
+
ftx.d3453 = 'DE'
|
759
|
+
ftx_in_header << ftx
|
760
|
+
end
|
761
|
+
|
762
|
+
s01 = Verkettung01_Felder.new
|
763
|
+
if seg=s_msg[/[12][25]01/].first # 1201, 2201, 1501, 2501
|
764
|
+
s01.v_nad_by = seg.bbn_rechnungsempfaenger
|
765
|
+
s01.v_nad_ds = seg.bbn_warenlieferant
|
766
|
+
s01.v_nad_su_va = seg.ust_ident_nr_lieferant
|
767
|
+
s01.v_nad_su_fc = seg.steuer_nr
|
768
|
+
s01.v_nad_by_va = seg.ust_ident_nr_erwerber
|
769
|
+
s01.ls_a_kz = seg.ls_auftrag_kz
|
770
|
+
s01.ls_a_nr1 = seg.ls_auftrag_nr_1
|
771
|
+
s01.ls_a_nr2 = seg.ls_auftrag_nr_2
|
772
|
+
else
|
773
|
+
s01.ls_a_kz = 0
|
774
|
+
end
|
775
|
+
|
776
|
+
# Naming convention:
|
777
|
+
#
|
778
|
+
# shd = SEDAS header record, e.g. a SA12/22 or a SA15/25
|
779
|
+
# str = SEDAS trailer record, e.g. a SA14/24 or a SA17/27
|
780
|
+
#
|
781
|
+
shd = s_msg[/[12][25]00/].first # Must exist due to SEDAS msg definition!
|
782
|
+
all_str = s_msg[/[12][47]00/] # Expect one per VAT rate, one at least
|
783
|
+
|
784
|
+
ls_auftrag_array = [[shd.ls_auftrag_kz_1, shd.ls_auftrag_nr_1, 1],
|
785
|
+
[shd.ls_auftrag_kz_2, shd.ls_auftrag_nr_2, 2],
|
786
|
+
[shd.ls_auftrag_kz_3, shd.ls_auftrag_nr_3, 3],
|
787
|
+
[shd.ls_auftrag_kz_4, shd.ls_auftrag_nr_4, 4],
|
788
|
+
[shd.ls_auftrag_kz_5, shd.ls_auftrag_nr_5, 5]]
|
789
|
+
|
790
|
+
summe_77 = all_str.inject(0){|sum, s| sum + s.endbetrag}
|
791
|
+
summe_131 = 0 # Evtl. erst Skonto addieren, siehe ALC (EAB)
|
792
|
+
vz = summe_77<=>0 # Vorzeichen, Unterscheidung Rechnung(+1)/Gutschrift(-1)
|
793
|
+
|
794
|
+
# BGM
|
795
|
+
#
|
796
|
+
bgm = @msg.new_segment("BGM")
|
797
|
+
bgm.cC002.d1001 = (vz < 0) ? 381 : 380
|
798
|
+
bgm.cC106.d1004 = shd.beleg_nr
|
799
|
+
bgm.d1225 = 9
|
800
|
+
@msg.add(bgm)
|
801
|
+
|
802
|
+
# All DTM
|
803
|
+
#
|
804
|
+
@msg.add_dtm(:d2005=> 137, :digits=> 5, :d2380=>shd.datum_rechnung)
|
805
|
+
if shd.lieferdatum==0
|
806
|
+
warn "Re-Nr #{shd.beleg_nr}, Pos-Nr #{shd.positions_nr}: " +
|
807
|
+
"Lieferdatum fehlt - verwende Belegdatum!"
|
808
|
+
@msg.add_dtm(:d2005=> 35, :d2380=> shd.datum_rechnung)
|
809
|
+
else
|
810
|
+
@msg.add_dtm(:d2005=> 35, :d2380=> shd.lieferdatum)
|
811
|
+
end
|
812
|
+
|
813
|
+
[
|
814
|
+
[shd.ls_auftrag_kz, shd.ls_auftrag_nr, shd.auftrags_nr_besteller, 1],
|
815
|
+
[s01.ls_a_kz, s01.ls_a_nr1, s01.ls_a_nr2, 2]
|
816
|
+
].each do |a|
|
817
|
+
kz, nr1, nr2, no = a
|
818
|
+
next unless kz==2 # Lieferdatum von-bis (0JJMMTT)
|
819
|
+
dt = if nr1.is_a? String
|
820
|
+
@curr_year[0,2]+nr1[1,6]+@curr_year[0,2]+nr2[1,6]
|
821
|
+
else
|
822
|
+
@curr_year[0,2]+"%06d" % nr1 + @curr_year[0,2]+"%06d" % nr2
|
823
|
+
end
|
824
|
+
@msg.add_dtm( :d2005=>35, :d2380=>dt, :d2379=>718 ) # CCYYMMDD-CCYYMMDD
|
825
|
+
end
|
826
|
+
|
827
|
+
# ALI
|
828
|
+
#
|
829
|
+
# Anmerkung 18:
|
830
|
+
if shd.b_vereinbarung_kz_1==6 || shd.b_vereinbarung_kz_2==6
|
831
|
+
ali = @msg.new_segment("ALI")
|
832
|
+
bgm.a4183[0].value = 15
|
833
|
+
@msg.add ali
|
834
|
+
end
|
835
|
+
# FIXME: Trap case "b_vereinbarung_kz_x != 1 or 6
|
836
|
+
|
837
|
+
# All FTX
|
838
|
+
#
|
839
|
+
ftx_in_header.each {|obj| @msg.add(obj)}
|
840
|
+
|
841
|
+
# SG1: RFF-DTM
|
842
|
+
#
|
843
|
+
case q=shd.reli_zahlungsempfaenger_kz # Nr. 2, Anmerkung 17
|
844
|
+
when 0 # empty - skip
|
845
|
+
when 1
|
846
|
+
@msg.add_rff( :d1153=>'ABO', :d1154=> shd.rz_eintrag_1 )
|
847
|
+
@msg.add_dtm( :d2005=> 171, :d2380=> shd.rz_eintrag_2 )
|
848
|
+
when 2
|
849
|
+
@msg.add_rff( :d1153=>'ABO', :d1154=> shd.rz_eintrag_1 )
|
850
|
+
when 6
|
851
|
+
@msg.add_rff( :d1153=>'IV', :d1154=> shd.rz_eintrag_1 )
|
852
|
+
@msg.add_dtm( :d2005=> 171, :d2380=> shd.rz_eintrag_2 )
|
853
|
+
when 7
|
854
|
+
@msg.add_rff( :d1153=>'IV', :d1154=> shd.rz_eintrag_1 )
|
855
|
+
else
|
856
|
+
raise "S.-Rechnung: 'Kennzeichen' ungueltig: #{q}"
|
857
|
+
end
|
858
|
+
|
859
|
+
[
|
860
|
+
[shd.ls_auftrag_kz, shd.ls_auftrag_nr, shd.auftrags_nr_besteller, 1],
|
861
|
+
[s01.ls_a_kz, s01.ls_a_nr1, s01.ls_a_nr2, 2]
|
862
|
+
].each do |a|
|
863
|
+
kz, nr1, nr2, no = a
|
864
|
+
case kz # Nr. 3, Anmerkung 1
|
865
|
+
when nil # treat as empty, should not occur
|
866
|
+
$log.warn("ls_auftrag_kz (#{no}) fehlt!")
|
867
|
+
when 0 # empty - skip
|
868
|
+
when 1
|
869
|
+
@msg.add_rff( :d1153=>'DQ', :d1154=> nr1 )
|
870
|
+
@msg.add_rff( :d1153=>'ON', :d1154=> nr2 )
|
871
|
+
when 2 # skip - treated earlier (DTM)
|
872
|
+
when 3
|
873
|
+
@msg.add_rff( :d1153=>'ON', :d1154=> nr1 )
|
874
|
+
when 4
|
875
|
+
@msg.add_rff( :d1153=>'DQ', :d1154=> nr1 )
|
876
|
+
else
|
877
|
+
raise "Kennzeichen LS/Auftrag (#{no}) ungueltig (Anm. 1): '#{kz}'"
|
878
|
+
end
|
879
|
+
end
|
880
|
+
|
881
|
+
ls_auftrag_array.each do |a|
|
882
|
+
kz, nr1, no = a
|
883
|
+
case kz # Nr. 3, Anmerkung 3
|
884
|
+
when 0 # empty - skip
|
885
|
+
when 5 # Lieferscheinnummer
|
886
|
+
@msg.add_rff( :d1153=>'DQ', :d1154=> nr1 )
|
887
|
+
when 6 # Auftragsnummer
|
888
|
+
@msg.add_rff( :d1153=>'ON', :d1154=> nr1 )
|
889
|
+
else
|
890
|
+
raise "Kennzeichen LS/Auftrag (#{no}) ungueltig (Anm. 3): '#{kz}'"
|
891
|
+
end
|
892
|
+
end # each
|
893
|
+
|
894
|
+
# SG2: NAD-RFF
|
895
|
+
#
|
896
|
+
@msg.add_nad( :d3035=>'SU', :d3039=> shd.bbn_lieferant )
|
897
|
+
@msg.add_rff( :d1153=>'VA', :d1154=> s01.v_nad_su_va )
|
898
|
+
@msg.add_rff( :d1153=>'FC', :d1154=> s01.v_nad_su_fc )
|
899
|
+
|
900
|
+
bbn = s01.v_nad_by
|
901
|
+
bbn = shd.bbn_rechnungsempfaenger if bbn.nil? || bbn == 0
|
902
|
+
@msg.add_nad( :d3035=>'BY', :d3039=> bbn )
|
903
|
+
@msg.add_rff( :d1153=>'VA', :d1154=> s01.v_nad_by_va )
|
904
|
+
# Anmerkung 18:
|
905
|
+
@msg.add_rff( :d1153=>'YC1',:d1154=> shd.b_vereinbarung_1 ) if
|
906
|
+
shd.b_vereinbarung_kz_1 == 1
|
907
|
+
@msg.add_rff( :d1153=>'YC1',:d1154=> shd.b_vereinbarung_2 ) if
|
908
|
+
shd.b_vereinbarung_kz_2 == 1
|
909
|
+
|
910
|
+
case kz=shd.warenempfaenger_kz
|
911
|
+
when 1
|
912
|
+
bbn = shd.bbn_warenempfaenger.to_s + "%06d" % shd.interne_nr
|
913
|
+
@msg.add_nad( :d3035=>'DP', :d3039=> bbn )
|
914
|
+
when 2
|
915
|
+
s51 = master_data['51'].find{|s| s.refpos_nr == shd.positions_nr}
|
916
|
+
raise "Sorry - SA51 fehlt fuer pos_nr={shd.positions_nr}" unless s51
|
917
|
+
@msg.add_nad( :d3035=>'DP', :d3036_1=> s51.name_warenempfaenger,
|
918
|
+
:d3164=> s51.ort,
|
919
|
+
:d3042_1=> s51.strasse_postfach,
|
920
|
+
:d3251=> s51.plz_1==0 ? s51.plz_2.strip : s51.plz_1 )
|
921
|
+
# @msg.add_rff( :d1153=>'IA', :d1154=> shd.interne_nr )
|
922
|
+
when 3
|
923
|
+
bbn = shd.bbn_warenempfaenger
|
924
|
+
@msg.add_nad( :d3035=>'DP', :d3039=> bbn )
|
925
|
+
else
|
926
|
+
raise "Warenempfaenger-bbs: 'Kennzeichen' ungueltig: '#{kz}'"
|
927
|
+
end
|
928
|
+
|
929
|
+
# TAX-MOA SG6
|
930
|
+
#
|
931
|
+
all_str.each {|s| @msg.add_tax( :ust_kz=> s.ust_kz, :pos_nr=> s.positions_nr ) }
|
932
|
+
|
933
|
+
# ALC-MOA SG16
|
934
|
+
#
|
935
|
+
all_str.each do |s|
|
936
|
+
kz, betrag = s.fracht_verpackung_kz, s.frachtbelastung
|
937
|
+
next if kz == 0
|
938
|
+
params = {}
|
939
|
+
params[:d5463] = betrag > 0 ? 'C' : 'A'
|
940
|
+
params[:d7161] = case kz
|
941
|
+
when 1: 'FC'
|
942
|
+
when 2: 'PC'
|
943
|
+
when 3: 'IN'
|
944
|
+
when 4,5,6,7: 'SH'
|
945
|
+
else raise "'Fracht/Verpackungs-Kennzeichen' ungueltig: '#{kz}'"
|
946
|
+
end
|
947
|
+
@msg.add_alc( params )
|
948
|
+
@msg.add_moa( :d5025=> 8, :d5004=> betrag.abs/100.0 )
|
949
|
+
end
|
950
|
+
|
951
|
+
all_str.each do |s|
|
952
|
+
betrag = s.skonto
|
953
|
+
next if betrag == 0
|
954
|
+
@msg.add_alc( :d5463=> 'A', :d1227=> 1, :d7161=> 'EAB' )
|
955
|
+
@msg.add_moa( :d5025=> 8, :d5004=> betrag.abs/100.0 )
|
956
|
+
summe_131 += betrag
|
957
|
+
warn "Skonto positiv: #{betrag}, pos_nr=#{s.positions_nr}" if vz*betrag>0
|
958
|
+
end
|
959
|
+
|
960
|
+
all_str.each do |s| # Also see code at item level, SG39
|
961
|
+
[[s.rabatt_kz_1, s.rechnungsrabatt_1, 1],
|
962
|
+
[s.rabatt_kz_2, s.rechnungsrabatt_2, 2],
|
963
|
+
[s.rabatt_kz_3, s.rechnungsrabatt_3, 3],
|
964
|
+
[s.rabatt_kz_4, s.rechnungsrabatt_4, 4]].each do |a|
|
965
|
+
kz, betrag, no = a
|
966
|
+
next if kz == 0
|
967
|
+
|
968
|
+
params = {
|
969
|
+
:d5463=> betrag < 0 ? 'A' : 'C',
|
970
|
+
:d7161=> 'DI', :d1227=> kz%10 - 1
|
971
|
+
}
|
972
|
+
params[:d1227] = nil unless params[:d1227].between?(1,4)
|
973
|
+
@msg.add_alc( params )
|
974
|
+
|
975
|
+
case (kz - kz%10)/10
|
976
|
+
when 1..4, 6
|
977
|
+
@msg.add_moa( :d5025=> 8, :d5004=> betrag.abs/100.0 )
|
978
|
+
when 5
|
979
|
+
@msg.add_moa( :d5025=> 8, :d5004=> betrag.abs/100.0 )
|
980
|
+
pri_aab.d5125 = 'AAA' if pri_aab # Why?
|
981
|
+
when 7
|
982
|
+
@msg.add_pcd( :d5245=> 3, :d5482=> betrag.abs/10000.0 )
|
983
|
+
when 8
|
984
|
+
@msg.add_rte( :d5419=> 1, :d5420=> betrag.abs/10000.0 )
|
985
|
+
else
|
986
|
+
raise "ALC: Unbekanntes 'Rabatt-Kennzeichen: '#{kz}'"
|
987
|
+
end
|
988
|
+
end
|
989
|
+
end
|
990
|
+
|
991
|
+
# Items: Map elsewhere
|
992
|
+
#
|
993
|
+
s_msg[/[12][36]00/].each do |s|
|
994
|
+
map_16_to_38x_item( s.descendants_and_self, item_counter,
|
995
|
+
master_data, vz )
|
996
|
+
item_counter += 2
|
997
|
+
end
|
998
|
+
|
999
|
+
# Trailer
|
1000
|
+
#
|
1001
|
+
uns = @msg.new_segment("UNS")
|
1002
|
+
uns.d0081 = 'S'
|
1003
|
+
@msg.add(uns)
|
1004
|
+
|
1005
|
+
# MOA SG50
|
1006
|
+
#
|
1007
|
+
summe_402, summe_124, summe_79 = 0, 0, 0
|
1008
|
+
# summe_77, summe_131: siehe oben
|
1009
|
+
all_str.each do |s|
|
1010
|
+
if s.b_vereinbarung_kz_1 == 2 # Nr. 27
|
1011
|
+
summe_402 += s.b_vereinbarung_1
|
1012
|
+
end
|
1013
|
+
# FIXME: Really try to add both occurrences?
|
1014
|
+
if s.b_vereinbarung_kz_2 == 2 # Nr. 27
|
1015
|
+
summe_402 += s.b_vereinbarung_2
|
1016
|
+
end
|
1017
|
+
summe_124 += s.umsatzsteuer
|
1018
|
+
summe_131 += s.rechnungsrabatt_gesamt
|
1019
|
+
summe_79 += s.warenbetrag
|
1020
|
+
# summe_77 += s.endbetrag # See beginning
|
1021
|
+
end
|
1022
|
+
@msg.add_moa( :d5025=> 402, :d5004=> vz*summe_402/100.0 ) if summe_402 != 0
|
1023
|
+
@msg.add_moa( :d5025=> 131, :d5004=> vz*summe_131/100.0 ) if summe_131 != 0
|
1024
|
+
@msg.add_moa( :d5025=> 125, :d5004=> vz*(summe_77 - summe_124)/100.0 )
|
1025
|
+
@msg.add_moa( :d5025=> 124, :d5004=> vz*summe_124/100.0 ) if summe_124 != 0
|
1026
|
+
@msg.add_moa( :d5025=> 79, :d5004=> vz*summe_79 /100.0 ) if summe_79 != 0
|
1027
|
+
@msg.add_moa( :d5025=> 77, :d5004=> vz*summe_77 /100.0 ) if summe_77 != 0
|
1028
|
+
|
1029
|
+
# TAX-MOA SG52, only if more than 1 trailer record found
|
1030
|
+
#
|
1031
|
+
all_str.each do |s|
|
1032
|
+
if s.ust_kz != 0 # Nr. 9
|
1033
|
+
@msg.add_tax( :ust_kz=> s.ust_kz, :pos_nr=> s.positions_nr )
|
1034
|
+
@msg.add_moa( :d5025=> 79, :d5004=> vz*s.warenbetrag/100.0 )
|
1035
|
+
@msg.add_moa( :d5025=> 124, :d5004=> vz*s.umsatzsteuer/100.0 )
|
1036
|
+
betrag = s.rechnungsrabatt_gesamt + s.skonto
|
1037
|
+
@msg.add_moa( :d5025=> 131, :d5004=> vz*betrag/100.0 ) if betrag != 0
|
1038
|
+
end
|
1039
|
+
end if all_str.size > 1
|
1040
|
+
|
1041
|
+
@p.add @msg, false
|
1042
|
+
end
|
1043
|
+
|
1044
|
+
|
1045
|
+
def map_16_to_38x_item( segments, item_counter, master_data, vz )
|
1046
|
+
# Lookahead / out-of-sequence segments first:
|
1047
|
+
ftx_in_item = []
|
1048
|
+
segments.find_all{|seg| seg.name=~/[12][36]08/}.each do |seg|
|
1049
|
+
ftx = @msg.new_segment("FTX")
|
1050
|
+
ftx.d4451 = 'ZZZ'
|
1051
|
+
ftx.cC108.a4440[0].value = seg.freitext.strip
|
1052
|
+
ftx.d3453 = 'DE'
|
1053
|
+
ftx_in_item << ftx
|
1054
|
+
end
|
1055
|
+
|
1056
|
+
s02 = Verkettung02_Felder.new
|
1057
|
+
if seg=segments.find{|s| s.name=~/[12][36]02/} # just 0..1 expected
|
1058
|
+
s02.ust_prozentsatz = seg.ust_prozentsatz
|
1059
|
+
s02.preisschluessel = seg.preisschluessel
|
1060
|
+
s02.komma_kz_p = seg.komma_kz_p
|
1061
|
+
s02.grundpreis = seg.grundpreis
|
1062
|
+
s02.mengenschluessel = seg.mengenschluessel
|
1063
|
+
s02.komma_kz_m = seg.komma_kz_m
|
1064
|
+
s02.menge = seg.menge
|
1065
|
+
s02.empty = false
|
1066
|
+
else
|
1067
|
+
s02.empty = true
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
# Now do the serial mapping
|
1071
|
+
segments.each do |seg|
|
1072
|
+
|
1073
|
+
seg_id = seg.name
|
1074
|
+
seg_id += ' ' + seg.sg_name if seg.sg_name
|
1075
|
+
case seg_id
|
1076
|
+
when /[12][36]00 SG1/
|
1077
|
+
# FIXME: Linear search - consider a hash for fast lookup via ean.
|
1078
|
+
s5000 = master_data.find{|s| s.name=='5000' && s.ean==seg.ean}
|
1079
|
+
raise "SA 50 fehlt fuer EAN #{seg.ean}, pos_nr=#{seg.positions_nr}" unless s5000
|
1080
|
+
|
1081
|
+
@msg.add_lin( :d1082=> item_counter, :d7140=> seg.ean)
|
1082
|
+
|
1083
|
+
# PIA
|
1084
|
+
#
|
1085
|
+
@msg.add_pia( :d4347=> 1, :d7140=> s5000.artikel_nr, :d7143=> 'SA')
|
1086
|
+
|
1087
|
+
# IMD
|
1088
|
+
#
|
1089
|
+
@msg.add_imd( :d7077=> 'C', :d7009=> 'IN', :d7009_3055=> 9)
|
1090
|
+
@msg.add_imd( :d7077=> 'A', :d7008_1=> s5000.langtext)
|
1091
|
+
|
1092
|
+
# QTY
|
1093
|
+
#
|
1094
|
+
if s02.empty || s02.mengenschluessel == 0 || s02.komma_kz_m == 0
|
1095
|
+
mengenschluessel, komma_kz_m, menge =
|
1096
|
+
seg.mengenschluessel, seg.komma_kz_m, seg.menge
|
1097
|
+
else
|
1098
|
+
mengenschluessel, komma_kz_m, menge =
|
1099
|
+
s02.mengenschluessel, s02.komma_kz_m, s02.menge
|
1100
|
+
end
|
1101
|
+
if s02.empty || s02.preisschluessel == 0 || s02.komma_kz_p == 0
|
1102
|
+
preisschluessel, komma_kz_p, grundpreis =
|
1103
|
+
seg.preisschluessel, seg.komma_kz_p, seg.grundpreis
|
1104
|
+
else
|
1105
|
+
preisschluessel, komma_kz_p, grundpreis =
|
1106
|
+
s02.preisschluessel, s02.komma_kz_p, s02.grundpreis
|
1107
|
+
end
|
1108
|
+
@msg.add_qty( :d6063=> preisschluessel == 9 ? 192 : 47, # w/o charge?
|
1109
|
+
:d6060=> to_value( komma_kz_m, vz*menge ),
|
1110
|
+
:qkey=> mengenschluessel )
|
1111
|
+
|
1112
|
+
# All FTX
|
1113
|
+
#
|
1114
|
+
ftx_in_item.each {|obj| @msg.add(obj)}
|
1115
|
+
|
1116
|
+
# MOA
|
1117
|
+
#
|
1118
|
+
betrag = seg.artikelrabatt_gesamt
|
1119
|
+
@msg.add_moa( :d5025=> 131, :d5004=> vz*betrag/100.0 ) if betrag != 0
|
1120
|
+
betrag = seg.warenwert
|
1121
|
+
@msg.add_moa( :d5025=> 203, :d5004=> vz*betrag/100.0 ) if betrag != 0
|
1122
|
+
if seg.b_vereinbarung_kz_2 == 3
|
1123
|
+
@msg.add_moa( :d5025=> 204, :d5004=> vz*seg.b_vereinbarung_2/10.0 )
|
1124
|
+
end
|
1125
|
+
|
1126
|
+
# PRI
|
1127
|
+
#
|
1128
|
+
pri_aab =
|
1129
|
+
@msg.add_pri(:d5125=>'AAB', :d5118=>to_value( komma_kz_p,grundpreis),
|
1130
|
+
:pkey=>preisschluessel, :qkey=>mengenschluessel )
|
1131
|
+
if seg.schluessel_kz == 1
|
1132
|
+
@msg.add_pri( :d5125=>'AAE',
|
1133
|
+
:d5118=>to_value( seg.komma_kz, seg.sondereintrag ) )
|
1134
|
+
# :pkey=>preisschluessel, :qkey=>mengenschluessel)
|
1135
|
+
elsif seg.schluessel_kz == 3
|
1136
|
+
@msg.add_pri( :d5125=>'AAA',
|
1137
|
+
:d5118=>to_value( seg.komma_kz, seg.sondereintrag ) )
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
# RFF-DTM SG30
|
1141
|
+
#
|
1142
|
+
if seg.b_vereinbarung_kz_2 == 5
|
1143
|
+
@msg.add_rff( :d1153=>'AAK', :d1154=> seg.b_vereinbarung_2 )
|
1144
|
+
end
|
1145
|
+
|
1146
|
+
# TAX-MOA
|
1147
|
+
#
|
1148
|
+
@msg.add_tax( :ust_kz=> seg.umsatzsteuer_kz, :pos_nr=> seg.positions_nr )
|
1149
|
+
|
1150
|
+
|
1151
|
+
# ALC SG39
|
1152
|
+
#
|
1153
|
+
[[seg.rabatt_kz_1, seg.artikelrabatt_1, 1],
|
1154
|
+
[seg.rabatt_kz_2, seg.artikelrabatt_2, 2],
|
1155
|
+
[seg.rabatt_kz_3, seg.artikelrabatt_3, 3],
|
1156
|
+
[seg.rabatt_kz_4, seg.artikelrabatt_4, 4]].each do |a|
|
1157
|
+
kz, betrag, no = a
|
1158
|
+
next if kz == 0
|
1159
|
+
|
1160
|
+
params = {
|
1161
|
+
:d5463=> betrag < 0 ? 'A' : 'C',
|
1162
|
+
:d7161=> 'DI', :d1227=> kz%10 - 1
|
1163
|
+
}
|
1164
|
+
params[:d1227] = nil unless params[:d1227].between?(1,4)
|
1165
|
+
@msg.add_alc( params )
|
1166
|
+
|
1167
|
+
case (kz - kz%10)/10
|
1168
|
+
when 1..4, 6
|
1169
|
+
@msg.add_moa( :d5025=> 8, :d5004=> betrag.abs/100.0 )
|
1170
|
+
when 5
|
1171
|
+
@msg.add_moa( :d5025=> 8, :d5004=> betrag.abs/100.0 )
|
1172
|
+
pri_aab.d5125 = 'AAA' if pri_aab # Why?
|
1173
|
+
when 7
|
1174
|
+
@msg.add_pcd( :d5245=> 3, :d5482=> betrag.abs/10000.0 )
|
1175
|
+
when 8
|
1176
|
+
@msg.add_rte( :d5419=> 1, :d5420=> betrag.abs/10000.0 )
|
1177
|
+
else
|
1178
|
+
raise "ALC: Unbekanntes 'Rabatt-Kennzeichen: '#{kz}'"
|
1179
|
+
end
|
1180
|
+
end
|
1181
|
+
|
1182
|
+
# Sub-line info
|
1183
|
+
#
|
1184
|
+
@msg.add_lin( :d1082=> item_counter+1,
|
1185
|
+
:d7140=> s5000.kleinste_ean,
|
1186
|
+
:c829_d1082 => item_counter )
|
1187
|
+
|
1188
|
+
@msg.add_pia( :d4347=> 1, :d7140=> "%04d" % s5000.klassifikation,
|
1189
|
+
:d7143=> 'GN')
|
1190
|
+
@msg.add_imd( :d7077=> 'C', :d7009=> 'CU', :d7009_3055=> 9)
|
1191
|
+
@msg.add_qty( :d6063=> 59, :d6060=> s5000.menge_ean )
|
1192
|
+
|
1193
|
+
|
1194
|
+
when /[12][36]0[2468] SG1/
|
1195
|
+
# ignored here - handled by lookahead section
|
1196
|
+
|
1197
|
+
else
|
1198
|
+
raise "Segment-Id #{seg_id} hier nicht erwartet!"
|
1199
|
+
end
|
1200
|
+
end
|
1201
|
+
end
|
1202
|
+
|
1203
|
+
|
1204
|
+
def map_29_to_393( s_msg )
|
1205
|
+
@msg = @p.new_message( @msg_params )
|
1206
|
+
|
1207
|
+
raise "Verkettung 01 zu SA29 nicht unterstuetzt - sorry" unless s_msg['2901'].empty?
|
1208
|
+
raise "Verkettung 02 zu SA29 nicht unterstuetzt - sorry" unless s_msg['2902'].empty?
|
1209
|
+
|
1210
|
+
all_s29 = s_msg['2900']
|
1211
|
+
s29 = all_s29.first # Must exist due to SEDAS msg definition!
|
1212
|
+
|
1213
|
+
bgm = @msg.new_segment("BGM")
|
1214
|
+
bgm.cC002.d1001 = 393
|
1215
|
+
raise "Erste SA29 muss eine 'Rechnungslistennummer' enthalten!" unless s29.reli_kz == 2
|
1216
|
+
bgm.cC106.d1004 = s29.nummer
|
1217
|
+
bgm.d1225 = 9
|
1218
|
+
@msg.add(bgm)
|
1219
|
+
|
1220
|
+
@msg.add_dtm(:d2005=> 137, :digits=> 5, :d2380=>s29.datum_reli)
|
1221
|
+
|
1222
|
+
# SG1: RFF-DTM
|
1223
|
+
#
|
1224
|
+
if (nr=s29.abkommen_nr) != 0
|
1225
|
+
@msg.add_rff( :d1153=>'CT', :d1154=> nr )
|
1226
|
+
end
|
1227
|
+
|
1228
|
+
# SG2: NAD group
|
1229
|
+
#
|
1230
|
+
@msg.add_nad( :d3035=>'SU', :d3039=> s29.bbn_lieferant )
|
1231
|
+
@msg.add_nad( :d3035=>'BY', :d3039=> s29.bbn_rechnungslistenempfaenger )
|
1232
|
+
@msg.add_nad( :d3035=>'PE', :d3039=> s29.bbn_zahlungsempfaenger )
|
1233
|
+
@msg.add_nad( :d3035=>'PR', :d3039=> s29.bbn_zahlungsleistender )
|
1234
|
+
|
1235
|
+
|
1236
|
+
# TAX-MOA SG6
|
1237
|
+
#
|
1238
|
+
@msg.add_tax( :ust_kz=> s29.ust_kz, :pos_nr=> s29.positions_nr )
|
1239
|
+
# Just first occurrence of SA29 ok?
|
1240
|
+
|
1241
|
+
# PAT-DTM SG8
|
1242
|
+
#
|
1243
|
+
if (vdat=s29.valutadatum) != 0
|
1244
|
+
@msg.add_pat( :d4279=> 3 )
|
1245
|
+
@msg.add_dtm( :d2005=> 209, :d2380=> vdat )
|
1246
|
+
end
|
1247
|
+
|
1248
|
+
|
1249
|
+
# Trailer
|
1250
|
+
#
|
1251
|
+
uns = @msg.new_segment("UNS")
|
1252
|
+
uns.d0081 = 'S'
|
1253
|
+
@msg.add(uns)
|
1254
|
+
|
1255
|
+
# MOA SG50
|
1256
|
+
#
|
1257
|
+
|
1258
|
+
summe_124, summe_125, summe_86 = summe_9 = 0, 0, 0, 0
|
1259
|
+
all_s29.each do |s|
|
1260
|
+
summe_124 += s.umsatzsteuer
|
1261
|
+
summe_86 += s.endbetrag
|
1262
|
+
summe_9 += s.zahlbetrag
|
1263
|
+
end
|
1264
|
+
@msg.add_moa( :d5025=> 86, :d5004=> summe_86 /100.0 )
|
1265
|
+
@msg.add_moa( :d5025=> 9, :d5004=> summe_9 /100.0 )
|
1266
|
+
@msg.add_moa( :d5025=> 124, :d5004=> summe_124/100.0 )
|
1267
|
+
@msg.add_moa( :d5025=> 125, :d5004=> (summe_86 - summe_124)/100.0 )
|
1268
|
+
|
1269
|
+
|
1270
|
+
# TAX-MOA SG52, only if more than 1 S29 record found
|
1271
|
+
#
|
1272
|
+
all_s29.each do |s|
|
1273
|
+
@msg.add_tax( :ust_kz=> s.ust_kz, :pos_nr=> s.positions_nr )
|
1274
|
+
@msg.add_moa( :d5025=> 124, :d5004=> s.umsatzsteuer/100.0 )
|
1275
|
+
@msg.add_moa( :d5025=> 125, :d5004=> (s.zahlbetrag - s.umsatzsteuer)/100.0 )
|
1276
|
+
@msg.add_moa( :d5025=> 86, :d5004=> s.endbetrag/100.0 )
|
1277
|
+
end if all_s29.size > 1
|
1278
|
+
|
1279
|
+
@p.add @msg
|
1280
|
+
end
|
1281
|
+
|
1282
|
+
|
1283
|
+
def initialize(src, dest)
|
1284
|
+
@msg = nil
|
1285
|
+
@with_ung = false
|
1286
|
+
@s = src
|
1287
|
+
@ic = dest
|
1288
|
+
@p = @ic # Current parent of a message - either the interchange or a group
|
1289
|
+
@msg_params = {
|
1290
|
+
:msg_type => 'INVOIC',
|
1291
|
+
:version => 'D',
|
1292
|
+
:release => '01B',
|
1293
|
+
:resp_agency => 'UN',
|
1294
|
+
:assigned_code => 'EAN010'
|
1295
|
+
}
|
1296
|
+
@curr_year = Time.now.year.to_s
|
1297
|
+
end
|
1298
|
+
|
1299
|
+
|
1300
|
+
def go
|
1301
|
+
map_00_to_unb(@s.header)
|
1302
|
+
@s.each do |grp|
|
1303
|
+
map_01_to_ung(grp.header) if self.with_ung
|
1304
|
+
master_data = grp.find {|msg| msg.name=='50'}
|
1305
|
+
grp.each do |msg|
|
1306
|
+
case msg.name
|
1307
|
+
when '12', '22'
|
1308
|
+
map_12_to_325( msg, master_data )
|
1309
|
+
when '15', '25'
|
1310
|
+
map_15_to_38x( msg, master_data )
|
1311
|
+
when '29'
|
1312
|
+
map_29_to_393( msg )
|
1313
|
+
when '50'
|
1314
|
+
# Skip master data
|
1315
|
+
else
|
1316
|
+
raise "SA#{msg.name} nicht unterstuetzt - sorry"
|
1317
|
+
end
|
1318
|
+
end
|
1319
|
+
end
|
1320
|
+
end
|
1321
|
+
|
1322
|
+
|
1323
|
+
def validate
|
1324
|
+
@ic.validate
|
1325
|
+
end
|
1326
|
+
|
1327
|
+
def write(hnd)
|
1328
|
+
@ic.write(hnd)
|
1329
|
+
end
|
1330
|
+
end
|
1331
|
+
|
1332
|
+
|
1333
|
+
#
|
1334
|
+
# MAIN
|
1335
|
+
#
|
1336
|
+
|
1337
|
+
$log = Logger.new(STDERR)
|
1338
|
+
$log.level = Logger::INFO
|
1339
|
+
$log.datetime_format = "%H:%M:%S"
|
1340
|
+
|
1341
|
+
params = {
|
1342
|
+
:show_una => true,
|
1343
|
+
:charset => 'UNOC',
|
1344
|
+
:version => 3,
|
1345
|
+
:interchange_control_reference => Time.now.to_f.to_s[0...14] ,
|
1346
|
+
# :application_reference => 'EANCOM' ,
|
1347
|
+
# :output_mode => :verbatim,
|
1348
|
+
# :acknowledgment_request => true,
|
1349
|
+
:interchange_agreement_id => 'EANCOM'+'' , # your ref here!
|
1350
|
+
:test_indicator => 1,
|
1351
|
+
}
|
1352
|
+
ic = EDI::E::Interchange.new( params )
|
1353
|
+
|
1354
|
+
|
1355
|
+
with_ung = false
|
1356
|
+
|
1357
|
+
while ARGV[0] =~ /^-(\w)/
|
1358
|
+
opt = ARGV.shift
|
1359
|
+
case $1
|
1360
|
+
when 'v' # verbose mode - here: use formatted output
|
1361
|
+
ic.output_mode = :indented
|
1362
|
+
when 'g'
|
1363
|
+
with_ung = true
|
1364
|
+
else
|
1365
|
+
raise "Option nicht zulaessig: #{opt}"
|
1366
|
+
end
|
1367
|
+
end
|
1368
|
+
|
1369
|
+
$log.info "Input einlesen..."
|
1370
|
+
sedas_ic = EDI::S::Interchange.parse(File.open(ARGV[0], 'r'), false)
|
1371
|
+
$log.info "Input validieren..."
|
1372
|
+
sedas_ic.validate
|
1373
|
+
$log.info "Zuordnen..."
|
1374
|
+
map = SEDAS_to_EANCOM02_Map_INVOIC.new( sedas_ic, ic )
|
1375
|
+
#
|
1376
|
+
# Add UNG/UNE if there is more than one group per file
|
1377
|
+
#
|
1378
|
+
map.with_ung = (sedas_ic.size > 1) # with_ung
|
1379
|
+
map.go
|
1380
|
+
$log.info "Output validieren..."
|
1381
|
+
ic.validate
|
1382
|
+
$log.info "Ergebnis schreiben..."
|
1383
|
+
$stdout.write ic
|
1384
|
+
$log.info "Fertig."
|
1385
|
+
# ic.inspect
|