solidus_shipstation 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/.bundle/config +2 -0
  3. data/.circleci/config.yml +41 -0
  4. data/.gem_release.yml +5 -0
  5. data/.github/stale.yml +17 -0
  6. data/.github_changelog_generator +2 -0
  7. data/.gitignore +20 -0
  8. data/.rspec +2 -0
  9. data/.rubocop.yml +13 -0
  10. data/.rubocop_todo.yml +40 -0
  11. data/CHANGELOG.md +36 -0
  12. data/Gemfile +33 -0
  13. data/LICENSE +26 -0
  14. data/README.md +208 -0
  15. data/Rakefile +6 -0
  16. data/app/assets/javascripts/spree/backend/solidus_shipstation.js +2 -0
  17. data/app/assets/javascripts/spree/frontend/solidus_shipstation.js +2 -0
  18. data/app/assets/stylesheets/spree/backend/solidus_shipstation.css +4 -0
  19. data/app/assets/stylesheets/spree/frontend/solidus_shipstation.css +4 -0
  20. data/app/controllers/spree/shipstation_controller.rb +45 -0
  21. data/app/decorators/models/solidus_shipstation/spree/shipment_decorator.rb +33 -0
  22. data/app/helpers/solidus_shipstation/export_helper.rb +32 -0
  23. data/app/jobs/solidus_shipstation/api/schedule_shipment_syncs_job.rb +19 -0
  24. data/app/jobs/solidus_shipstation/api/sync_shipments_job.rb +41 -0
  25. data/app/queries/solidus_shipstation/shipment/between_query.rb +14 -0
  26. data/app/queries/solidus_shipstation/shipment/exportable_query.rb +24 -0
  27. data/app/queries/solidus_shipstation/shipment/pending_api_sync_query.rb +63 -0
  28. data/app/views/spree/shipstation/export.xml.builder +58 -0
  29. data/bin/console +17 -0
  30. data/bin/rails +7 -0
  31. data/bin/rails-engine +13 -0
  32. data/bin/rails-sandbox +16 -0
  33. data/bin/rake +7 -0
  34. data/bin/sandbox +86 -0
  35. data/bin/setup +8 -0
  36. data/config/locales/en.yml +5 -0
  37. data/config/routes.rb +6 -0
  38. data/db/migrate/20210220093010_add_shipstation_api_sync_fields.rb +9 -0
  39. data/lib/generators/solidus_shipstation/install/install_generator.rb +27 -0
  40. data/lib/generators/solidus_shipstation/install/templates/initializer.rb +62 -0
  41. data/lib/solidus_shipstation.rb +16 -0
  42. data/lib/solidus_shipstation/api/batch_syncer.rb +70 -0
  43. data/lib/solidus_shipstation/api/client.rb +38 -0
  44. data/lib/solidus_shipstation/api/rate_limited_error.rb +23 -0
  45. data/lib/solidus_shipstation/api/request_error.rb +33 -0
  46. data/lib/solidus_shipstation/api/request_runner.rb +50 -0
  47. data/lib/solidus_shipstation/api/shipment_serializer.rb +84 -0
  48. data/lib/solidus_shipstation/api/threshold_verifier.rb +28 -0
  49. data/lib/solidus_shipstation/configuration.rb +44 -0
  50. data/lib/solidus_shipstation/engine.rb +19 -0
  51. data/lib/solidus_shipstation/errors.rb +23 -0
  52. data/lib/solidus_shipstation/shipment_notice.rb +58 -0
  53. data/lib/solidus_shipstation/testing_support/factories.rb +4 -0
  54. data/lib/solidus_shipstation/version.rb +5 -0
  55. data/solidus_shipstation.gemspec +40 -0
  56. data/spec/controllers/spree/shipstation_controller_spec.rb +103 -0
  57. data/spec/fixtures/shipstation_xml_schema.xsd +171 -0
  58. data/spec/jobs/solidus_shipstation/api/schedule_shipment_syncs_job_spec.rb +32 -0
  59. data/spec/jobs/solidus_shipstation/api/sync_shipments_job_spec.rb +102 -0
  60. data/spec/lib/solidus_shipstation/api/batch_syncer_spec.rb +229 -0
  61. data/spec/lib/solidus_shipstation/api/client_spec.rb +120 -0
  62. data/spec/lib/solidus_shipstation/api/rate_limited_error_spec.rb +21 -0
  63. data/spec/lib/solidus_shipstation/api/request_error_spec.rb +20 -0
  64. data/spec/lib/solidus_shipstation/api/request_runner_spec.rb +64 -0
  65. data/spec/lib/solidus_shipstation/api/shipment_serializer_spec.rb +12 -0
  66. data/spec/lib/solidus_shipstation/api/threshold_verifier_spec.rb +61 -0
  67. data/spec/lib/solidus_shipstation/shipment_notice_spec.rb +111 -0
  68. data/spec/lib/solidus_shipstation_spec.rb +9 -0
  69. data/spec/models/spree/shipment_spec.rb +49 -0
  70. data/spec/queries/solidus_shipstation/shipment/between_query_spec.rb +53 -0
  71. data/spec/queries/solidus_shipstation/shipment/exportable_query_spec.rb +53 -0
  72. data/spec/queries/solidus_shipstation/shipment/pending_api_sync_query_spec.rb +37 -0
  73. data/spec/spec_helper.rb +31 -0
  74. data/spec/support/configuration_helper.rb +13 -0
  75. data/spec/support/controllers.rb +1 -0
  76. data/spec/support/webmock.rb +3 -0
  77. data/spec/support/xsd.rb +5 -0
  78. metadata +248 -0
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusShipstation
4
+ module Api
5
+ class ThresholdVerifier
6
+ class << self
7
+ def call(shipment)
8
+ return false unless shipment.order.completed?
9
+
10
+ !!(shipment_requires_creation?(shipment) || shipment_requires_update?(shipment))
11
+ end
12
+
13
+ private
14
+
15
+ def shipment_requires_creation?(shipment)
16
+ shipment.shipstation_synced_at.nil? &&
17
+ Time.zone.now - shipment.order.updated_at < SolidusShipstation.config.api_sync_threshold
18
+ end
19
+
20
+ def shipment_requires_update?(shipment)
21
+ shipment.shipstation_synced_at &&
22
+ shipment.shipstation_synced_at < shipment.order.updated_at &&
23
+ Time.zone.now - shipment.order.updated_at < SolidusShipstation.config.api_sync_threshold
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusShipstation
4
+ class Configuration
5
+ attr_accessor(
6
+ :username,
7
+ :password,
8
+ :weight_units,
9
+ :ssl_encrypted,
10
+ :capture_at_notification,
11
+ :export_canceled_shipments,
12
+ :api_batch_size,
13
+ :api_sync_threshold,
14
+ :api_shipment_serializer,
15
+ :api_key,
16
+ :api_secret,
17
+ :api_shipment_matcher,
18
+ :error_handler,
19
+ )
20
+
21
+ def initialize
22
+ @api_batch_size = 100
23
+ @api_sync_threshold = 7.days
24
+ @error_handler = ->(_error, _extra = {}) {
25
+ Rails.logger.error "#{error.inspect} (#{extra.inspect})"
26
+ }
27
+ @api_shipment_matcher = proc do |shipstation_order, shipments|
28
+ shipments.find { |shipment| shipment.number == shipstation_order['orderNumber'] }
29
+ end
30
+ end
31
+ end
32
+
33
+ class << self
34
+ def configuration
35
+ @configuration ||= Configuration.new
36
+ end
37
+
38
+ alias config configuration
39
+
40
+ def configure
41
+ yield configuration
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'solidus_core'
4
+ require 'solidus_support'
5
+
6
+ module SolidusShipstation
7
+ class Engine < Rails::Engine
8
+ include SolidusSupport::EngineExtensions
9
+
10
+ isolate_namespace ::Spree
11
+
12
+ engine_name 'solidus_shipstation'
13
+
14
+ # use rspec for tests
15
+ config.generators do |g|
16
+ g.test_framework :rspec
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusShipstation
4
+ class Error < StandardError; end
5
+
6
+ class OrderNotPaidError < Error
7
+ def initialize(order, *args)
8
+ super("Order #{order.number} is not paid and capture_at_notification is false", *args)
9
+ end
10
+ end
11
+
12
+ class ShipmentNotFoundError < Error
13
+ def initialize(shipment_number, *args)
14
+ super("Could not find shipment with number #{shipment_number}", *args)
15
+ end
16
+ end
17
+
18
+ class PaymentError < Error
19
+ def initialize(payment, *args)
20
+ super("Could not process payment #{payment.id}", *args)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusShipstation
4
+ class ShipmentNotice
5
+ attr_reader :shipment_number, :shipment_tracking
6
+
7
+ class << self
8
+ def from_payload(params)
9
+ new(
10
+ shipment_number: params[:order_number],
11
+ shipment_tracking: params[:tracking_number],
12
+ )
13
+ end
14
+ end
15
+
16
+ def initialize(shipment_number:, shipment_tracking:)
17
+ @shipment_number = shipment_number
18
+ @shipment_tracking = shipment_tracking
19
+ end
20
+
21
+ def apply
22
+ unless shipment
23
+ raise ShipmentNotFoundError, shipment
24
+ end
25
+
26
+ process_payment
27
+ ship_shipment
28
+
29
+ shipment
30
+ end
31
+
32
+ private
33
+
34
+ def shipment
35
+ @shipment ||= ::Spree::Shipment.find_by(number: shipment_number)
36
+ end
37
+
38
+ def process_payment
39
+ return if shipment.order.paid?
40
+
41
+ unless SolidusShipstation.configuration.capture_at_notification
42
+ raise OrderNotPaidError, shipment.order
43
+ end
44
+
45
+ shipment.order.payments.pending.each do |payment|
46
+ payment.capture!
47
+ rescue ::Spree::Core::GatewayError
48
+ raise PaymentError, payment
49
+ end
50
+ end
51
+
52
+ def ship_shipment
53
+ shipment.update!(tracking: shipment_tracking)
54
+ shipment.ship! if shipment.can_ship?
55
+ shipment.order.recalculate
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.define do
4
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusShipstation
4
+ VERSION = '1.0.0'
5
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/solidus_shipstation/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'solidus_shipstation'
7
+ spec.version = SolidusShipstation::VERSION
8
+ spec.authors = ['Stephen Puiszis']
9
+ spec.email = 'steve@tablexi.com'
10
+
11
+ spec.summary = 'Solidus/ShipStation Integration'
12
+ spec.description = 'Integrates ShipStation API with Solidus. Supports exporting shipments and importing tracking numbers'
13
+ spec.homepage = 'https://github.com/solidusio-contrib/solidus_shipstation'
14
+ spec.license = 'BSD-3-Clause'
15
+
16
+ spec.metadata['homepage_uri'] = spec.homepage
17
+ spec.metadata['source_code_uri'] = 'https://github.com/solidusio-contrib/solidus_shipstation'
18
+ spec.metadata['changelog_uri'] = 'https://github.com/solidusio-contrib/solidus_shipstation/blob/master/CHANGELOG.md'
19
+
20
+ spec.required_ruby_version = Gem::Requirement.new('~> 2.5')
21
+
22
+ # Specify which files should be added to the gem when it is released.
23
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
+ files = Dir.chdir(__dir__) { `git ls-files -z`.split("\x0") }
25
+
26
+ spec.files = files.grep_v(%r{^(test|spec|features)/})
27
+ spec.test_files = files.grep(%r{^(test|spec|features)/})
28
+ spec.bindir = "exe"
29
+ spec.executables = files.grep(%r{^exe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+
32
+ spec.add_dependency 'httparty', '~> 0.18'
33
+ spec.add_dependency 'solidus_core', ['>= 2.0.0', '< 4']
34
+ spec.add_dependency 'solidus_support', '~> 0.5'
35
+
36
+ spec.add_development_dependency 'rails-controller-testing'
37
+ spec.add_development_dependency 'rspec-xsd'
38
+ spec.add_development_dependency 'solidus_dev_support', '~> 2.5'
39
+ spec.add_development_dependency 'webmock'
40
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Spree::ShipstationController do
4
+ render_views
5
+
6
+ describe '#export' do
7
+ context 'when the authentication is invalid' do
8
+ it 'returns an error error' do
9
+ get :export, params: { format: 'xml' }
10
+
11
+ expect(response.status).to eq(401)
12
+ end
13
+ end
14
+
15
+ context 'when the authentication is valid' do
16
+ it 'responds with 200 OK' do
17
+ stub_shipstation_auth
18
+ create(:order_ready_to_ship)
19
+
20
+ get :export,
21
+ params: {
22
+ start_date: 1.day.ago.strftime('%m/%d/%Y %H:%M'),
23
+ end_date: 1.day.from_now.strftime('%m/%d/%Y %H:%M'),
24
+ format: 'xml'
25
+ }
26
+
27
+ expect(response.status).to eq(200)
28
+ end
29
+
30
+ it 'generates ShipStation-compliant XML' do
31
+ stub_shipstation_auth
32
+ create(:order_ready_to_ship)
33
+
34
+ get :export, params: {
35
+ start_date: 1.day.ago.strftime('%m/%d/%Y %H:%M'),
36
+ end_date: 1.day.from_now.strftime('%m/%d/%Y %H:%M'),
37
+ format: 'xml'
38
+ }
39
+
40
+ expect(response.body).to pass_validation('spec/fixtures/shipstation_xml_schema.xsd')
41
+ end
42
+ end
43
+ end
44
+
45
+ describe '#shipnotify' do
46
+ context 'when the authentication is valid' do
47
+ context 'when the shipment can be found' do
48
+ it 'responds with 200 OK' do
49
+ stub_shipstation_auth
50
+ shipment = create(:order_ready_to_ship).shipments.first
51
+
52
+ post :shipnotify, params: {
53
+ order_number: shipment.number,
54
+ tracking_number: '123456',
55
+ format: 'xml',
56
+ }
57
+ shipment.reload
58
+
59
+ expect(response.status).to eq(200)
60
+ end
61
+
62
+ it 'updates the shipment' do
63
+ stub_shipstation_auth
64
+ shipment = create(:order_ready_to_ship).shipments.first
65
+
66
+ post :shipnotify, params: {
67
+ order_number: shipment.number,
68
+ tracking_number: '123456',
69
+ format: 'xml',
70
+ }
71
+ shipment.reload
72
+
73
+ expect(shipment).to have_attributes(
74
+ tracking: '123456',
75
+ state: 'shipped',
76
+ shipped_at: an_instance_of(ActiveSupport::TimeWithZone),
77
+ )
78
+ end
79
+ end
80
+
81
+ context 'when the shipment cannot be found' do
82
+ it 'responds with 400 Bad Request' do
83
+ stub_shipstation_auth
84
+ shipment = create(:order_ready_to_ship).shipments.first
85
+
86
+ post :shipnotify, params: {
87
+ order_number: 'ABC123',
88
+ tracking_number: '123456',
89
+ format: 'xml',
90
+ }
91
+ shipment.reload
92
+
93
+ expect(response.status).to eq(400)
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ def stub_shipstation_auth(username = 'mario', password = 'lemieux')
100
+ stub_configuration(username: username, password: password)
101
+ request.headers['Authorization'] = ActionController::HttpAuthentication::Basic.encode_credentials(username, password)
102
+ end
103
+ end
@@ -0,0 +1,171 @@
1
+ <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
2
+ <xs:element name="Orders">
3
+ <xs:complexType>
4
+ <xs:sequence>
5
+ <xs:element name="Order" maxOccurs="unbounded" minOccurs="0">
6
+ <xs:complexType>
7
+ <xs:all>
8
+ <xs:element type="String50" name="OrderID" minOccurs="0"/>
9
+ <xs:element type="String50" name="OrderNumber"/>
10
+ <xs:element type="DateTime" name="OrderDate"/>
11
+ <xs:element type="String50" name="OrderStatus"/>
12
+ <xs:element type="DateTime" name="LastModified"/>
13
+ <xs:element type="String100" name="ShippingMethod" minOccurs="0"/>
14
+ <xs:element type="String50" name="PaymentMethod" minOccurs="0"/>
15
+ <xs:element type="xs:float" name="OrderTotal"/>
16
+ <xs:element type="xs:float" name="TaxAmount" minOccurs="0"/>
17
+ <xs:element type="xs:float" name="ShippingAmount" minOccurs="0"/>
18
+ <xs:element type="String1000" name="CustomerNotes" minOccurs="0"/>
19
+ <xs:element type="String1000" name="InternalNotes" minOccurs="0"/>
20
+ <xs:element type="xs:boolean" name="Gift" minOccurs="0"/>
21
+ <xs:element type="String1000" name="GiftMessage" minOccurs="0"/>
22
+ <xs:element type="String100" name="CustomField1" minOccurs="0"/>
23
+ <xs:element type="String100" name="CustomField2" minOccurs="0"/>
24
+ <xs:element type="String100" name="CustomField3" minOccurs="0"/>
25
+ <xs:element type="String100" name="RequestedWarehouse" minOccurs="0"/>
26
+ <xs:element type="String50" name="Source" minOccurs="0" />
27
+ <xs:element name="Customer">
28
+ <xs:complexType>
29
+ <xs:all>
30
+ <xs:element type="String100" name="CustomerCode"/>
31
+ <xs:element name="BillTo">
32
+ <xs:complexType>
33
+ <xs:all>
34
+ <xs:element type="String100" name="Name"/>
35
+ <xs:element type="String100" name="Company" minOccurs="0"/>
36
+ <xs:element type="String50" name="Phone" minOccurs="0"/>
37
+ <xs:element type="Email" name="Email" minOccurs="0"/>
38
+ <xs:element type="String200" name="Address1" minOccurs="0"/>
39
+ <xs:element type="String200" name="Address2" minOccurs="0"/>
40
+ <xs:element type="String100" name="City" minOccurs="0"/>
41
+ <xs:element type="String100" name="State" minOccurs="0"/>
42
+ <xs:element type="String50" name="PostalCode" minOccurs="0"/>
43
+ <xs:element type="StringExactly2" name="Country" minOccurs="0"/>
44
+ </xs:all>
45
+ </xs:complexType>
46
+ </xs:element>
47
+ <xs:element name="ShipTo">
48
+ <xs:complexType>
49
+ <xs:all>
50
+ <xs:element type="String100" name="Name"/>
51
+ <xs:element type="String100" name="Company" minOccurs="0"/>
52
+ <xs:element type="String200" name="Address1"/>
53
+ <xs:element type="String200" name="Address2" minOccurs="0"/>
54
+ <xs:element type="String100" name="City"/>
55
+ <xs:element type="String100" name="State" minOccurs="0"/>
56
+ <xs:element type="String50" name="PostalCode" minOccurs="1"/>
57
+ <xs:element type="StringExactly2" name="Country"/>
58
+ <xs:element type="String50" name="Phone" minOccurs="0"/>
59
+ </xs:all>
60
+ </xs:complexType>
61
+ </xs:element>
62
+ </xs:all>
63
+ </xs:complexType>
64
+ </xs:element>
65
+ <xs:element name="Items">
66
+ <xs:complexType>
67
+ <xs:sequence>
68
+ <xs:element name="Item" maxOccurs="unbounded" minOccurs="0">
69
+ <xs:complexType>
70
+ <xs:all>
71
+ <xs:element type="String50" name="LineItemID" minOccurs="0"/>
72
+ <xs:element type="String100" name="SKU"/>
73
+ <xs:element type="String200" name="Name"/>
74
+ <xs:element type="xs:boolean" name="Adjustment" minOccurs="0"/>
75
+ <xs:element type="xs:anyURI" name="ImageUrl" minOccurs="0"/>
76
+ <xs:element type="xs:float" name="Weight" minOccurs="0"/>
77
+ <xs:element name="WeightUnits" minOccurs="0">
78
+ <xs:simpleType>
79
+ <xs:restriction base="xs:string">
80
+ <xs:pattern value="|pound|pounds|lb|lbs|gram|grams|gm|oz|ounces|Pound|Pounds|Lb|Lbs|Gram|Grams|Gm|Oz|Ounces|POUND|POUNDS|LB|LBS|GRAM|GRAMS|GM|OZ|OUNCES"/>
81
+ </xs:restriction>
82
+ </xs:simpleType>
83
+ </xs:element>
84
+ <xs:element name="Dimensions" minOccurs="0">
85
+ <xs:complexType>
86
+ <xs:all>
87
+ <xs:element name="DimensionUnits" minOccurs="0">
88
+ <xs:simpleType>
89
+ <xs:restriction base="xs:string">
90
+ <xs:pattern value="|inch|inches|in|centimeter|centimeters|cm|INCH|INCHES|IN|CENTIMETER|CENTIMETERS|CM"/>
91
+ </xs:restriction>
92
+ </xs:simpleType>
93
+ </xs:element>
94
+ <xs:element type="xs:float" name="Length"/>
95
+ <xs:element type="xs:float" name="Width"/>
96
+ <xs:element type="xs:float" name="Height"/>
97
+ </xs:all>
98
+ </xs:complexType>
99
+ </xs:element>
100
+ <xs:element type="xs:int" name="Quantity"/>
101
+ <xs:element type="xs:float" name="UnitPrice"/>
102
+ <xs:element type="String100" name="Location" minOccurs="0"/>
103
+ <xs:element name="Options" minOccurs="0">
104
+ <xs:complexType>
105
+ <xs:sequence>
106
+ <xs:element name="Option" maxOccurs="100" minOccurs="0">
107
+ <xs:complexType>
108
+ <xs:all>
109
+ <xs:element type="String100" name="Name"/>
110
+ <xs:element type="String100" name="Value"/>
111
+ <xs:element type="xs:float" name="Weight" minOccurs="0"/>
112
+ </xs:all>
113
+ </xs:complexType>
114
+ </xs:element>
115
+ </xs:sequence>
116
+ </xs:complexType>
117
+ </xs:element>
118
+ </xs:all>
119
+ </xs:complexType>
120
+ </xs:element>
121
+ </xs:sequence>
122
+ </xs:complexType>
123
+ </xs:element>
124
+ </xs:all>
125
+ </xs:complexType>
126
+ </xs:element>
127
+ </xs:sequence>
128
+ <xs:attribute type="xs:short" name="pages"/>
129
+ </xs:complexType>
130
+ </xs:element>
131
+ <xs:simpleType name="DateTime">
132
+ <xs:restriction base="xs:string">
133
+ <xs:pattern value="[0-9][0-9]?/[0-9][0-9]?/[0-9][0-9][0-9]?[0-9]? [0-9][0-9]?:[0-9][0-9]?:?[0-9]?[0-9]?. ?[aApP]?[mM]?"/>
134
+ </xs:restriction>
135
+ </xs:simpleType>
136
+ <xs:simpleType name="Email">
137
+ <xs:restriction base="xs:string">
138
+ </xs:restriction>
139
+ </xs:simpleType>
140
+ <xs:simpleType name="StringExactly2">
141
+ <xs:restriction base="xs:string">
142
+ <xs:minLength value="2"/>
143
+ <xs:maxLength value="2"/>
144
+ </xs:restriction>
145
+ </xs:simpleType>
146
+ <xs:simpleType name="String30">
147
+ <xs:restriction base="xs:string">
148
+ <xs:maxLength value="30"/>
149
+ </xs:restriction>
150
+ </xs:simpleType>
151
+ <xs:simpleType name="String50">
152
+ <xs:restriction base="xs:string">
153
+ <xs:maxLength value="50"/>
154
+ </xs:restriction>
155
+ </xs:simpleType>
156
+ <xs:simpleType name="String100">
157
+ <xs:restriction base="xs:string">
158
+ <xs:maxLength value="100"/>
159
+ </xs:restriction>
160
+ </xs:simpleType>
161
+ <xs:simpleType name="String200">
162
+ <xs:restriction base="xs:string">
163
+ <xs:maxLength value="200"/>
164
+ </xs:restriction>
165
+ </xs:simpleType>
166
+ <xs:simpleType name="String1000">
167
+ <xs:restriction base="xs:string">
168
+ <xs:maxLength value="1000"/>
169
+ </xs:restriction>
170
+ </xs:simpleType>
171
+ </xs:schema>