editx 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG ADDED
@@ -0,0 +1,2 @@
1
+ v0.1.0 (23rd March 2009)
2
+ - Initial Release
data/README.markdown ADDED
@@ -0,0 +1,33 @@
1
+ ## EDItX
2
+
3
+ The EDItX standard specifies a collection of XML schemas for Electronic
4
+ Document Interchange between trading partners in the publishing industry.
5
+
6
+ This library provides a slim layer of the formats and simplifies both reading a
7
+ nd writing of EDItX files in your ruby applications.
8
+
9
+ ## Installation
10
+
11
+ gem install editx
12
+
13
+ ## Usage
14
+
15
+ See the comments for each root message type for detailed usage info.
16
+
17
+ * EDItX::Order - For working with EDItX Trade Order messages
18
+
19
+ ## Licensing
20
+
21
+ This library is distributed under the terms of the MIT License. See the included file for
22
+ more detail.
23
+
24
+ ## Contributing
25
+
26
+ All suggestions and patches welcome, preferably via a git repository I can pull from.
27
+ To be honest, I'm not really expecting any, this is a niche library.
28
+
29
+ ## Further Reading
30
+
31
+ - The source: [http://github.com/yob/editx/tree/master](http://github.com/yob/editx/tree/master)
32
+ - Rubyforge project: [http://rubyforge.org/projects/rbook/](http://rubyforge.org/projects/rbook/)
33
+ - The official specs [http://www.editeur.org/editx/editx.html](http://www.editeur.org/editx/editx.html)
data/lib/editx.rb ADDED
@@ -0,0 +1,78 @@
1
+ require 'rubygems'
2
+ require 'bigdecimal'
3
+
4
+ # ensure we load the correct gem versions
5
+ gem 'roxml', '2.5.2'
6
+ gem 'andand'
7
+
8
+ # and now load the actual gems
9
+ require 'roxml'
10
+ require 'andand'
11
+
12
+ module EDItX
13
+ module Version #:nodoc:
14
+ Major = 0
15
+ Minor = 1
16
+ Tiny = 0
17
+
18
+ String = [Major, Minor, Tiny].join('.')
19
+ end
20
+
21
+ class Formatters
22
+ def self.decimal
23
+ lambda do |val|
24
+ if val.kind_of?(BigDecimal)
25
+ val.to_s("F")
26
+ else
27
+ val.to_s
28
+ end
29
+ end
30
+ end
31
+
32
+ def self.yyyymmdd
33
+ lambda do |val|
34
+ if val.nil? || !val.respond_to?(:strftime)
35
+ nil
36
+ else
37
+ val.strftime("%Y%m%d")
38
+ end
39
+ end
40
+ end
41
+
42
+ def self.two_digit
43
+ lambda do |val|
44
+ if val.nil?
45
+ nil
46
+ elsif val < 10
47
+ "0#{val}"
48
+ elsif val > 99
49
+ val.to_s[-2,2]
50
+ else
51
+ val.to_s
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ # silence some warnings from ROXML
59
+ unless ROXML.const_defined?("SILENCE_XML_NAME_WARNING")
60
+ ROXML::SILENCE_XML_NAME_WARNING = true
61
+ end
62
+
63
+ # core files
64
+ # - ordering is important, classes need to be defined before any
65
+ # other class can use them
66
+ require File.join(File.dirname(__FILE__), "editx", "order", "reference_coded")
67
+ require File.join(File.dirname(__FILE__), "editx", "order", "date_coded")
68
+ require File.join(File.dirname(__FILE__), "editx", "order", "party")
69
+ require File.join(File.dirname(__FILE__), "editx", "order", "product_id")
70
+ require File.join(File.dirname(__FILE__), "editx", "order", "order_item_qualifier_coded")
71
+ require File.join(File.dirname(__FILE__), "editx", "order", "price")
72
+ require File.join(File.dirname(__FILE__), "editx", "order", "discount_part")
73
+ require File.join(File.dirname(__FILE__), "editx", "order", "discount_detail")
74
+ require File.join(File.dirname(__FILE__), "editx", "order", "returns_condition_coded")
75
+ require File.join(File.dirname(__FILE__), "editx", "order", "returns_conditions")
76
+ require File.join(File.dirname(__FILE__), "editx", "order", "message")
77
+ require File.join(File.dirname(__FILE__), "editx", "order", "item_detail")
78
+ require File.join(File.dirname(__FILE__), "editx", "order")
@@ -0,0 +1,116 @@
1
+ require 'tempfile'
2
+
3
+ module EDItX
4
+ # A abstraction for creating and generating EDItX Trade Order messages
5
+ #
6
+ # == Generating a new order
7
+ #
8
+ # The fundamentals are fairly simple. You create a new Order object, set various
9
+ # attributes on it, then add 1 or more ItemDetail objects - 1 for each item you
10
+ # would like to order.
11
+ #
12
+ # msg = EDItX::Order.new
13
+ # msg.order_number = self.id
14
+ # msg.issue_date_time = self.created_at
15
+ # msg.fill_terms_code = "FillPartBackorderRemainderShipAsAvailable"
16
+ #
17
+ # (1..10).each do |idx|
18
+ # item = EDItX::Order::ItemDetail.new
19
+ # item.line_number = idx
20
+ #
21
+ # ean = EDItX::Order::ProductID.new$
22
+ # ean.type = "EAN13"$
23
+ # ean.identifier = "product code goes here"$
24
+ # item.identifiers << ean
25
+ #
26
+ # p = EDItX::Order::Price.new
27
+ # p.monetary_amount = 10.00
28
+ # item.prices << p
29
+ #
30
+ # item.title_detail = "Title and author here"
31
+ # item.order_quantity
32
+ # msg.items << item
33
+ # end
34
+ #
35
+ # puts msg.to_s
36
+ #
37
+ # The challenge comes in making sure you output a VALID order file. Several elements are
38
+ # compulsory - I reccommend having a copy of the spec open to check which elements you
39
+ # need to include, and valid options for elements like fill_terms_code.
40
+ #
41
+ # To check the validity of your output, save it to a file and run xmllint on it, using
42
+ # the schemas distributed with this gem:
43
+ #
44
+ # xmllint --valid --nonet --schema schemas/order_1_2.xsd testfile.ord
45
+ #
46
+ # Continue testing with that command until you get output like "testfile.ord validates".
47
+ #
48
+ class Order
49
+ include ROXML
50
+
51
+ xml_name "Order"
52
+
53
+ # header values
54
+ xml_accessor :version, :from => "@version", :as => BigDecimal, :to_xml => EDItX::Formatters.decimal
55
+ xml_accessor :order_number, :in => "Header", :from => "OrderNumber"
56
+ xml_accessor :issue_date_time, :in => "Header", :from => "IssueDateTime", :as => DateTime, :to_xml => EDItX::Formatters.yyyymmdd
57
+ xml_accessor :references, :in => "Header", :from => "ReferenceCoded", :as => [EDItX::Order::ReferenceCoded]
58
+ xml_accessor :purpose_code, :in => "Header", :from => "PurposeCode"
59
+ xml_accessor :currency_code, :in => "Header", :from => "CurrencyCode"
60
+ xml_accessor :country_code, :in => "Header", :from => "CountryCode"
61
+ xml_accessor :dates, :in => "Header", :from => "DateCoded", :as => [EDItX::Order::DateCoded]
62
+ xml_accessor :fill_terms_code, :in => "Header", :from => "FillTermsCode"
63
+ xml_accessor :buyer_party, :in => "Header", :from => "BuyerParty", :as => EDItX::Order::Party
64
+ xml_accessor :seller_party, :in => "Header", :from => "SellerParty", :as => EDItX::Order::Party
65
+ xml_accessor :ship_to_party, :in => "Header", :from => "ShipToParty", :as => EDItX::Order::Party
66
+ xml_accessor :bill_to_party, :in => "Header", :from => "BillToParty", :as => EDItX::Order::Party
67
+ xml_accessor :shipping_instructions_code, :in => "Header", :from => "ShippingInstructionsCode"
68
+ xml_accessor :invoice_instructions_code, :in => "Header", :from => "InvoiceInstructionsCode"
69
+ xml_accessor :discount_percentage, :in => "Header", :from => "DiscountPercentage", :as => BigDecimal, :to_xml => EDItX::Formatters.decimal
70
+
71
+ # detail
72
+ xml_accessor :items, :from => "ItemDetail", :as => [EDItX::Order::ItemDetail]
73
+
74
+ # footer / summary
75
+ xml_accessor :number_of_lines, :in => "Summary", :from => "NumberOfLines", :as => Fixnum
76
+ xml_accessor :units_ordered, :in => "Summary", :from => "UnitsOrdered", :as => Fixnum
77
+
78
+ def initialize
79
+ self.version = BigDecimal.new("1.2")
80
+ self.references = []
81
+ self.dates = []
82
+ self.items = []
83
+ end
84
+
85
+ def to_s
86
+ self.to_xml.to_s
87
+ end
88
+
89
+ def valid?
90
+ schema_path = File.join(File.dirname(__FILE__), "..", "..", "schemas")
91
+ case self.version
92
+ when BigDecimal.new("1.0")
93
+ schema_path << "/order_1_0.xsd"
94
+ when BigDecimal.new("1.1")
95
+ schema_path << "/order_1_1.xsd"
96
+ when BigDecimal.new("1.2")
97
+ schema_path << "/order_1_2.xsd"
98
+ else
99
+ raise ArgumentError, "version #{self.version} is invalid"
100
+ end
101
+
102
+ Tempfile.open("editx") do |tf|
103
+ tf.write self.to_s
104
+ tf.close
105
+
106
+ system("xmllint --schema #{schema_path} #{tf.path} &> /dev/null")
107
+ if $?.exitstatus == 0
108
+ return true
109
+ else
110
+ return false
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ end
@@ -0,0 +1,13 @@
1
+ module EDItX
2
+ class Order
3
+ class DateCoded
4
+ include ROXML
5
+
6
+ xml_name "DateCoded"
7
+
8
+ xml_accessor :date, :from => "Date", :as => Date, :to_xml => EDItX::Formatters.yyyymmdd
9
+ xml_accessor :qualifier_code, :from => "DateQualifierCode"
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,18 @@
1
+ module EDItX
2
+ class Order
3
+ class DiscountDetail
4
+ include ROXML
5
+
6
+ xml_name "DiscountDetail"
7
+
8
+ xml_accessor :code_type, :from => "DiscountCodeType"
9
+ xml_accessor :parts, :from => "DiscountPart", :as => [EDItX::Order::DiscountPart]
10
+
11
+ def initialize
12
+ @parts = []
13
+ end
14
+
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,14 @@
1
+ module EDItX
2
+ class Order
3
+ class DiscountPart
4
+ include ROXML
5
+
6
+ xml_name "DiscountPart"
7
+
8
+ xml_accessor :code, :from => "DiscountCode"
9
+ xml_accessor :percentage, :from => "DiscountPercentage"
10
+
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,33 @@
1
+ module EDItX
2
+ class Order
3
+ class ItemDetail
4
+ include ROXML
5
+
6
+ xml_name "ItemDetail"
7
+
8
+ xml_accessor :line_number, :from => "LineNumber", :as => Fixnum
9
+ xml_accessor :identifiers, :from => "ProductID", :as => [EDItX::Order::ProductID]
10
+ xml_accessor :title_detail, :in => "ItemDescription", :from => "TitleDetail"
11
+ xml_accessor :order_quantity, :from => "OrderQuantity", :as => Fixnum
12
+ xml_accessor :references, :from => "ReferenceCoded", :as => [EDItX::Order::ReferenceCoded]
13
+ xml_accessor :dates, :from => "DateCoded", :as => [EDItX::Order::DateCoded]
14
+ xml_accessor :fill_terms_code, :from => "FillTermsCode"
15
+ xml_accessor :qualifiers, :from => "OrderItemQualifierCoded", :as => [EDItX::Order::OrderItemQualifierCoded]
16
+ xml_accessor :prices, :in => "PricingDetail", :from => "Price", :as => [EDItX::Order::Price]
17
+ xml_accessor :discount_percentage, :in => "PricingDetail", :from => "DiscountPercentage", :as => BigDecimal
18
+ xml_accessor :discount_detail, :in => "PricingDetail", :from => "DiscountDetail", :as => [EDItX::Order::DiscountDetail]
19
+ xml_accessor :returns_conditions, :from => "ReturnsConditions", :as => [EDItX::Order::ReturnsConditions]
20
+ xml_accessor :messages, :from => "Message", :as => [EDItX::Order::Message]
21
+
22
+ def initialize
23
+ @identifiers = []
24
+ @references = []
25
+ @dates = []
26
+ @qualifiers = []
27
+ @prices = []
28
+ @returns_conditions = []
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,18 @@
1
+ module EDItX
2
+ class Order
3
+ class Message
4
+ include ROXML
5
+
6
+ xml_name "Message"
7
+
8
+ xml_accessor :type, :from => "MessageType"
9
+ xml_accessor :lines, :from => "MessageLine", :as => []
10
+
11
+ def initialize
12
+ @lines = []
13
+ end
14
+
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,14 @@
1
+ module EDItX
2
+ class Order
3
+ class OrderItemQualifierCoded
4
+ include ROXML
5
+
6
+ xml_name "OrderItemQualifierCoded"
7
+
8
+ xml_accessor :code_type, :from => "OrderItemQualifierCodeType"
9
+ xml_accessor :code, :from => "OrderItemQualifierCode"
10
+
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,12 @@
1
+ module EDItX
2
+ class Order
3
+ class Party
4
+ include ROXML
5
+
6
+ xml_accessor :id_type, :in => "PartyID", :from => "PartyIDType"
7
+ xml_accessor :id, :in => "PartyID", :from => "Identifier"
8
+ xml_accessor :name, :in => "PartyName", :from => "NameLine"
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ module EDItX
2
+ class Order
3
+ class Price
4
+ include ROXML
5
+
6
+ xml_name "Price"
7
+
8
+ xml_accessor :monetary_amount, :from => "MonetaryAmount", :as => BigDecimal
9
+ xml_accessor :currency_code, :from => "CurrencyCode"
10
+ xml_accessor :country_code, :from => "CountryCode"
11
+ xml_accessor :qualifier_code, :from => "PriceQualifierCode"
12
+
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,15 @@
1
+ module EDItX
2
+ class Order
3
+ class ProductID
4
+ include ROXML
5
+
6
+ xml_name "ProductID"
7
+
8
+ xml_accessor :type, :from => "ProductIDType"
9
+ xml_accessor :type_name, :from => "ProductIDType"
10
+ xml_accessor :identifier, :from => "Identifier"
11
+
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,15 @@
1
+ module EDItX
2
+ class Order
3
+ class ReferenceCoded
4
+
5
+ include ROXML
6
+
7
+ xml_name "ReferenceCoded"
8
+
9
+ xml_accessor :type_code, :from => "ReferenceTypeCode"
10
+ xml_accessor :number, :from => "ReferenceNumber"
11
+ xml_accessor :date, :from => "ReferenceDate", :as => Date, :to_xml => EDItX::Formatters.yyyymmdd
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ module EDItX
2
+ class Order
3
+ class ReturnsConditionCoded
4
+ include ROXML
5
+
6
+ xml_name "ReturnsConditionCoded"
7
+
8
+ xml_accessor :type, :from => "ReturnsConditionCodeType"
9
+ xml_accessor :code, :from => "ReturnsConditionCode"
10
+
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,19 @@
1
+ module EDItX
2
+ class Order
3
+ class ReturnsConditions
4
+ include ROXML
5
+
6
+ xml_name "ReturnsConditions"
7
+
8
+ xml_accessor :last_date_for_returns, :from => "LastDateForReturns", :as => DateTime, :to_xml => EDItX::Formatters.yyyymmdd
9
+ xml_accessor :max_returns_percentage, :from => "MaximumReturnsPercentage"
10
+ xml_accessor :max_returns_quantity, :from => "MaximumReturnsQuantity"
11
+ xml_accessor :conditions, :from => "ReturnsConditionCoded", :as => [EDItX::Order::ReturnsConditionCoded]
12
+
13
+ def initialize
14
+ @conditions = []
15
+ end
16
+
17
+ end
18
+ end
19
+ end