editx 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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