elibri_onix_mocks 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - ree
7
+ notifications:
8
+ email:
9
+ - p.szmielew@ava.waw.pl
10
+ - tomek@gildia.pl
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in elibri_onix_mocks.gemspec
4
+ gemspec
@@ -0,0 +1,32 @@
1
+ [![Build Status](https://secure.travis-ci.org/elibri/elibri_onix_mocks.png?branch=master)](http://travis-ci.org/elibri/elibri_onix_mocks)
2
+
3
+ Gem created for Mocking eLibri xml objects.
4
+ More info coming soon.
5
+
6
+ Basic usage:
7
+ ``Elibri::XmlMocks::Example.basic_product``
8
+
9
+ methods to create mock objects:
10
+ `basic_product` `book_example` `onix_record_identifiers_example` `onix_product_form_example`
11
+ `onix_epub_details_example` `onix_categories_example` `onix_languages_example`
12
+ `onix_measurement_example` `onix_sale_restrictions_example` `onix_audience_range_example`
13
+ `onix_publisher_info_example` `onix_subjects_example` `onix_edition_example` `onix_ebook_extent_example`
14
+ `onix_audiobook_extent_example` `onix_no_contributors_example` `onix_collective_work_example`
15
+ `onix_contributors_example` `onix_announced_product_example` `onix_preorder_product_example`
16
+ `onix_published_product_example` `onix_out_of_print_product_example` `onix_titles_example`
17
+ `onix_title_with_collection_example` `onix_texts_example` `onix_related_products_example`
18
+ `onix_supply_details_example` `onix_series_memberships_example` `onix_supporting_resources_example`
19
+ `onix_elibri_extensions_example` `contributor_mock` `review_mock` `supply_detail_mock` `imprint_mock`
20
+ `description_mock`
21
+
22
+ Each method take arguments in a hash form, where key is the name of attribute in mock object. Value can be string, array, another mock object - depend on situation.
23
+
24
+ For list of important attributes please look into lib/mocks/xml_mocks.rb file.
25
+
26
+ If you want to create eLibri xml from mock:
27
+ ``Elibri::ONIX::XMLGenerator.new(mock_object).to_s``
28
+
29
+ Creating product from xml:
30
+ ``Elibri::ONIX::Release_3_0::ONIXMessage.from_xml(xml_string)``
31
+
32
+ Therefore you can use it to test your api handling function - you will receive same xml from mock, as you will receive from actual elibri api (with different data ofc :))
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ desc "Running specs"
4
+ task :spec do |t|
5
+ exec "cd spec/ && bundle exec rspec elibri_onix_mocks_spec.rb"
6
+ end
7
+
8
+ task :default => ["spec"]
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "elibri_onix_mocks/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "elibri_onix_mocks"
7
+ s.version = ElibriOnixMocks::VERSION
8
+ s.authors = ["Piotr Szmielew"]
9
+ s.email = ["p.szmielew@ava.waw.pl"]
10
+ s.homepage = ""
11
+ s.summary = %q{Gem that allows you to mock eLibri style xmls}
12
+ s.description = %q{Usage: Elibri::XmlGenerator.basic_product etc}
13
+
14
+ s.rubyforge_project = "elibri_onix_mocks"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ s.add_development_dependency "rspec"
23
+ # s.add_development_dependency 'ruby-debug'
24
+ s.add_development_dependency 'rake'
25
+
26
+ # s.add_runtime_dependency "rest-client"
27
+ s.add_runtime_dependency "elibri_onix_dict"
28
+ s.add_runtime_dependency 'elibri_api_client'
29
+ s.add_runtime_dependency "mocha"
30
+ s.add_runtime_dependency "builder"
31
+ s.add_runtime_dependency "activesupport"
32
+ end
@@ -0,0 +1,14 @@
1
+ require 'active_support'
2
+ require 'ostruct'
3
+ require 'elibri_onix_dict'
4
+ require 'elibri_api_client'
5
+ require 'elibri_onix_mocks/onix_helpers'
6
+ require "elibri_onix_mocks/version"
7
+ require 'elibri_onix_mocks/mocks/mock_method_missing'
8
+ require 'elibri_onix_mocks/mocks/xml_mocks'
9
+ require 'elibri_onix_mocks/generators/xml_generator'
10
+ require 'elibri_onix_mocks/xml_variant'
11
+
12
+ module Elibri
13
+
14
+ end
@@ -0,0 +1,995 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'builder'
4
+
5
+ module Elibri
6
+ module ONIX
7
+
8
+ class XMLGenerator
9
+
10
+
11
+ SHORT_TAGS = YAML::load_file(File.dirname(__FILE__) + "/xml_tags.yml")
12
+ DOC_ORDER = ["record_identifiers", "publishing_status", "product_form", "contributors", "titles", "series_memberships", "measurement",
13
+ "sale_restrictions", "audience_range", "publisher_info", "extent", "edition", "languages", "epub_details",
14
+ "texts", "supporting_resources", "elibri_extensions"]
15
+ #"subjects", "related_products", "supply_details"
16
+ attr_reader :builder, :tags_type
17
+
18
+
19
+ def self.tag(builder, short_tags, tag_id, *args, &block)
20
+ if short_tags
21
+ if SHORT_TAGS[tag_id]
22
+ tag_id = SHORT_TAGS[tag_id]
23
+ elsif tag_id.starts_with?("elibri")
24
+ tag_id
25
+ else
26
+ raise "Unknow short tag for: #{tag_id}"
27
+ end
28
+ end
29
+ builder.__send__(tag_id, *args, &block)
30
+ end
31
+
32
+ def self.render_header(builder, options = {}, &block)
33
+ options.reverse_merge!({:short_tags => false, :elibri_onix_dialect => '3.0.1'})
34
+ short_tags = options[:short_tags]
35
+
36
+ builder.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
37
+ message_attributes = {:release => "3.0", :xmlns => "http://www.editeur.org/onix/3.0/reference", "xmlns:elibri" => "http://elibri.com.pl/ns/extensions"}
38
+ message_attributes.delete('xmlns:elibri') if options[:pure_onix]
39
+
40
+ builder.ONIXMessage message_attributes do
41
+ unless options[:pure_onix]
42
+ builder.elibri :Dialect, options[:elibri_onix_dialect] # potrzebne, aby parser wiedział jak interpretować niektóre tagi
43
+ end
44
+ tag(builder, short_tags, :Header) do
45
+ tag(builder, short_tags, :Sender) do
46
+ tag(builder, short_tags, :SenderName, "Elibri.com.pl")
47
+ tag(builder, short_tags, :ContactName, "Tomasz Meka")
48
+ tag(builder, short_tags, :EmailAddress, "kontakt@elibri.com.pl")
49
+ end
50
+ tag(builder, short_tags, :SentDateTime, Date.today.strftime("%Y%m%d"))
51
+ end
52
+ yield(builder) if block_given?
53
+ end
54
+ end
55
+
56
+
57
+ def initialize(products, options = {})
58
+ options.reverse_merge!({
59
+ :tags_type => :full,
60
+ :export_headers => true,
61
+ :elibri_onix_dialect => '3.0.1',
62
+ :comments => false,
63
+ :xml_variant => Elibri::XmlVariant::FULL_VARIANT
64
+ })
65
+
66
+ @xml_variant = options[:xml_variant]
67
+ raise ":xml_variant unspecified" if @xml_variant.blank? or !@xml_variant.kind_of?(::Elibri::XmlVariant)
68
+
69
+ @products = Array(products)
70
+ @tags_type = ActiveSupport::StringInquirer.new(options[:tags_type].to_s)
71
+ @comments = options[:comments]
72
+ @comment_kinds = options[:comment_kinds]
73
+ @out = []
74
+ @builder = Builder::XmlMarkup.new(:indent => 2, :target => @out)
75
+ @elibri_onix_dialect = options[:elibri_onix_dialect]
76
+ # Gdy true, ignorujemy rozszerzenia eLibri
77
+ @pure_onix = options[:pure_onix]
78
+
79
+ # W testach często nie chcę żadnych nagłówków - interesuje mnie tylko tag <Product>
80
+ if options[:export_headers]
81
+ ONIX::XMLGenerator.render_header(builder, :short_tags => tags_type.short?, :elibri_onix_dialect => @elibri_onix_dialect, :pure_onix => @pure_onix) do
82
+ render_products!
83
+ end
84
+ else
85
+ render_products!
86
+ end
87
+ end
88
+
89
+
90
+ def to_s
91
+ @out.join
92
+ end
93
+
94
+
95
+ # Zwróć dokumentację dla metod sekcji ONIX z bieżącego pliku. Dzięki temu dokumentacja ONIX jest generowana w locie
96
+ # i nie rozjedzie się z kodem. Dokumentacje można wygenerować tylko dla metod 'def export_XXX!'.
97
+ #
98
+ # Przykład dokumentowania:
99
+ # # @hidden_tags RecordReference NotificationType
100
+ # # @title Wymiary produktu
101
+ # # eLibri zachowuje tylko <strong>wysokość, szerokość, grubość oraz masę produktu.</strong> Dla produktów typu mapa, eksportujemy również jej skalę
102
+ # # w tagu &lt;MapScale&gt;
103
+ # def export_measurement!(product)
104
+ # [...]
105
+ # end
106
+ #
107
+ # @hidden_tags określa tagi ONIX, które należy zwinąć w celu zachowania czytelności XML`a.
108
+ # @title to tytuł sekcji a reszta to wieloliniowy opis.
109
+ #
110
+ # Dla każdej sekcji trzeba utworzyć odpowiednią metodę w Product::Examples, która zwróci stub produktu.
111
+ # Np. dla metody 'export_measurement!' w Product::Examples należy utworzyć metodę 'onix_measurement_example'.
112
+ def self.onix_sections_docs
113
+ # Wczytaj bieżący plik
114
+ code_lines = File.readlines(__FILE__)
115
+
116
+ section_docs = Array.new
117
+ # Dla każdej metody o sygnaturze 'def export_NAZWA_SEKCJI!' czytaj otaczające linie komentarzy:
118
+ ONIX::XMLGenerator.instance_methods.grep(/export_/).each_with_index do |method_name, section_idx|
119
+ section_docs[section_idx] ||= Hash.new
120
+ section_docs[section_idx][:section_name] = method_name[/export_(.*)!/, 1] # "export_supplier_identifier!" => "supplier_identifier"
121
+ section_docs[section_idx][:hidden_tags] = Array.new
122
+ section_docs[section_idx][:auto_render] = true
123
+
124
+ # Znajdź numer linii z definicją metody:
125
+ method_definition_line_idx = code_lines.find_index {|line| line.match(/^\s*def #{method_name}/)}
126
+
127
+ # Cofamy się w gorę kodu, aż do początku pliku w poszukiwaniu linii zawierającej tag @title w komentarzu.
128
+ (method_definition_line_idx-1).downto(0).each do |line_idx|
129
+ # Oczyść linię kodu ze znaku komentarza i zbędnych spacji:
130
+ line = code_lines[line_idx].strip.sub(/^\s*#\s*/, '#')
131
+ raise "Nieprawidłowy format dokumentacji dla metody #{method_name}" if line.match(/^end$/)
132
+ if md = line.match(/^\s*$/)
133
+ break
134
+ elsif md = line.match(/@render (.*)$/)
135
+ section_docs[section_idx][:auto_render] = false
136
+ render_call = "\n= render :partial => 'example', :locals => { :method => '#{md[1].strip}' }\n"
137
+ section_docs[section_idx][:description] = [render_call, section_docs[section_idx][:description]].join("\n")
138
+ elsif md = line.match(/@title (.*)$/)
139
+ section_docs[section_idx][:section_title] = md[1].gsub(/^#/, '')
140
+ elsif md = line.match(/@hidden_tags (.*)$/)
141
+ section_docs[section_idx][:hidden_tags] = md[1].gsub(/^#/, '').scan(/\w+/)
142
+ elsif line == '#'
143
+ section_docs[section_idx][:description] = ["\n%br/\n", section_docs[section_idx][:description]].join("\n")
144
+ else
145
+ section_docs[section_idx][:description] = [line.gsub(/^#/, ''), section_docs[section_idx][:description]].join("\n")
146
+ end
147
+ end
148
+ end
149
+ # Zwróć posortowane według kolejności sekcji:
150
+ section_docs.find_all { |section_hash| DOC_ORDER.index(section_hash[:section_name]) }.sort_by {|section_hash| DOC_ORDER.index(section_hash[:section_name]) }
151
+ end
152
+
153
+
154
+ protected
155
+
156
+ # Wstaw do XML`a komentarz
157
+ def comment(text, options = {})
158
+ if options[:kind] && @comment_kinds
159
+ Array(options[:kind]).each do |kind|
160
+ builder.comment!("$#{kind}$ #{text}")
161
+ end
162
+ elsif @comments
163
+ builder.comment!(text)
164
+ end
165
+ end
166
+
167
+
168
+ def comment_dictionary(description, dict, options = {})
169
+ indent = options[:indent] || 4
170
+ pretty_string = lambda {|dict_item| "\n" + " " * indent + "#{dict_item.onix_code} - #{dict_item.name}" }
171
+ case dict
172
+ when Symbol
173
+ dictionary_items = Elibri::ONIX::Dict::Release_3_0.const_get(dict)::ALL.map(&pretty_string)
174
+ when Array
175
+ dictionary_items = dict.map {|dict_item| "\n" + " " * indent + dict_item }
176
+ end
177
+
178
+ comment(description + dictionary_items.join, options)
179
+ end
180
+
181
+
182
+ def render_products!
183
+ @products.each do |product|
184
+ next unless product.public?
185
+
186
+ tag(:Product) do
187
+ export_record_identifiers!(product) #PR.1 + PR.2
188
+ if @xml_variant.includes_basic_meta?
189
+ tag(:DescriptiveDetail) do
190
+ export_product_form!(product) #PR.3
191
+ export_epub_details!(product) #PR.3
192
+ export_measurement!(product)
193
+ #jak się dodaje tytuł, który nie jest samodzielne w sprzedaży?
194
+ #jak się dodaje tytuł, który zostanie przeceniony?
195
+ export_series_memberships!(product) #P.5
196
+ export_titles!(product) #PR.6
197
+ export_contributors!(product) #PR.7
198
+ #PR.8 - konferencje
199
+ export_edition!(product) #PR.9
200
+ export_languages!(product) #PR.10
201
+ export_extent!(product) #PR.11
202
+ export_subjects!(product) #PR.12
203
+ export_audience_range!(product) if product.audience_range_present? #PR.13
204
+ end
205
+ end
206
+ if @xml_variant.includes_other_texts? || @xml_variant.includes_media_files?
207
+ tag(:CollateralDetail) do
208
+ if @xml_variant.includes_other_texts? #TODO zmienić nazwę wariantu
209
+ export_texts!(product) #PR.14
210
+ end
211
+ #P.15 - citywany kontent - sprawdzić
212
+ if @xml_variant.includes_media_files?
213
+ export_supporting_resources!(product) #PR.16 #TODO - to jest też do przerobienia
214
+ end
215
+ #P.17 - nagrody
216
+ end
217
+ end
218
+ remove_tag_if_empty!(:CollateralDetail)
219
+ #P.18 - ContentItem
220
+ tag(:PublishingDetail) do
221
+ export_publisher_info!(product) #P.19
222
+ export_publishing_status!(product) #PR.20
223
+ export_sale_restrictions!(product) if product.sale_restricted? #PR.21
224
+ end
225
+ remove_tag_if_empty!(:PublishingDetail)
226
+ #P.23 - related products
227
+ if product.facsimiles.present? or product.similar_products.present?
228
+ export_related_products!(product)
229
+ end
230
+ #P.24 - Market
231
+ #P.25 - market representation
232
+ if @xml_variant.includes_stocks?
233
+ export_supply_details!(product) #PR.26
234
+ end
235
+ #fake dla exportu ze sklepu - w elibri ten kod nie zadziała
236
+ # if @xml_variant.respond_to?(:cover_price?) && @xml_variant.cover_price?
237
+ # export_cover_price!(product) #fake, żeby jakoś te dane wysłać
238
+ # end
239
+ export_elibri_extensions!(product) unless @pure_onix
240
+ end
241
+ end
242
+ end
243
+
244
+
245
+ # Renderuj tag w XML`u za pomocą Buildera. Jeśli wybrano opcję krótkich tagów,
246
+ # wstaw krótki tag z hasha SHORT_TAGS.
247
+ def tag(tag_id, *args, &block)
248
+ self.class.tag(builder, tags_type.short?, tag_id, *args, &block)
249
+ end
250
+
251
+ def remove_tag_if_empty!(tag_name)
252
+ idx = @out.rindex("<#{tag_name}")
253
+ if idx
254
+ tail = @out[idx..-1].join.strip.gsub("\n", "").gsub(" ", "")
255
+ if tail == "<#{tag_name}></#{tag_name}>" #wycinaj końcówkę
256
+ (@out.size - idx + 1).times do #zmieniaj listę in-place
257
+ @out.pop
258
+ end
259
+ end
260
+ end
261
+ end
262
+
263
+ # @hidden_tags NotificationType DescriptiveDetail ProductSupply PublishingDetail
264
+ # @title Identyfikatory rekordu
265
+ # Każdy rekord w ONIX-ie posiada wewnętrzny identyfikator, który jest dowolnym ciągiem znaków, i jest przekazywany
266
+ # w tagu <strong>&lt;ProductIdentifier&gt;</strong>. Gwarantowana jest jego niezmienność.
267
+ #
268
+ #
269
+ # Oprócz tego każdy produkt może posiadać numer ISBN, EAN oraz jeden lub więcej identyfikatorów dostawców (np. numer w bazie Olesiejuka)
270
+ # Tutaj już nie ma gwarancji niezmienności, choć jest to bardzo rzadka sytuacja (np. wydrukowany został jednak inny numer ISBN na okładce,
271
+ # i wydawcnictwo zmienia wpis w eLibri)
272
+ def export_record_identifiers!(product)
273
+ comment 'Unikalne ID rekordu produktu', :kind => :onix_record_identifiers
274
+ tag(:RecordReference, product.record_reference) #doc
275
+ comment_dictionary "Typ powiadomienia", :NotificationType, :kind => :onix_publishing_status
276
+ tag(:NotificationType, product.notification_type.onix_code) # Notification confirmed on publication - Lista 1
277
+ if product.respond_to?(:deletion_text) && product.deletion_text.present?
278
+ comment "Występuje tylko gdy NotificationType == #{Elibri::ONIX::Dict::Release_3_0::NotificationType::DELETE}", :kind => :onix_record_identifiers
279
+ tag(:DeletionText, product.deletion_text)
280
+ end
281
+
282
+ if product.isbn_value
283
+ comment 'ISBN', :kind => :onix_record_identifiers
284
+ tag(:ProductIdentifier) do
285
+ tag(:ProductIDType, Elibri::ONIX::Dict::Release_3_0::ProductIDType::ISBN13) #lista 5
286
+ tag(:IDValue, product.isbn_value)
287
+ end
288
+ end
289
+
290
+ if product.ean.present? && product.ean != product.isbn_value
291
+ comment 'EAN-13 - gdy inny niż ISBN', :kind => :onix_record_identifiers
292
+
293
+ tag(:ProductIdentifier) do
294
+ tag(:ProductIDType, Elibri::ONIX::Dict::Release_3_0::ProductIDType::EAN)
295
+ tag(:IDValue, product.ean)
296
+ end
297
+ end
298
+
299
+ if @xml_variant.includes_stocks?
300
+ product.product_availabilities.each do |pa|
301
+ if pa.supplier_identifier.present?
302
+ comment "Identyfikator dostawcy: #{pa.supplier.name}", :kind => :onix_record_identifiers
303
+ tag(:ProductIdentifier) do
304
+ tag(:ProductIDType, Elibri::ONIX::Dict::Release_3_0::ProductIDType::PROPRIETARY) #lista 5
305
+ tag(:IDTypeName, pa.supplier.name)
306
+ tag(:IDValue, pa.supplier_identifier)
307
+ end
308
+ end
309
+ end
310
+ end
311
+ end
312
+
313
+
314
+ # @hidden_tags RecordReference NotificationType ProductIdentifier TitleDetail
315
+ # @title Forma produktu
316
+ # <strong>&lt;ProductForm&gt;</strong> określa typ produktu. Np. BA to książka.<br/>
317
+ # <strong>&lt;ProductComposition&gt;</strong> przybiera aktualnie zawsze wartość 00 - czyli że przedmiotem handlu jest pojedyncza książka.
318
+ # W przyszłości ulegnie to zmianie, gdy dodamy do eLibri obsługę pakietów książek. Pakiet książek to komplet kilku książek,
319
+ # z nowym numerem ISBN, i nową ceną, na ogół niższą, niż suma cen książek zawartych w pakiecie.
320
+ def export_product_form!(product)
321
+ comment 'W tej chwili tylko 00 - pojedynczy element', :kind => :onix_product_form
322
+ tag(:ProductComposition, '00') #lista 2 - Single-item retail product
323
+
324
+ if product.product_form_onix_code
325
+ comment_dictionary "Format produktu", :ProductFormCode, :indent => 10, :kind => [:onix_product_form, :onix_epub_details]
326
+ tag(:ProductForm, product.product_form_onix_code)
327
+ end
328
+
329
+ if product.product_form_detail_onix_code
330
+ comment_dictionary "Szczegóły formatu produktu", :ProductFormDetail, :indent => 10, :kind => :onix_epub_details
331
+ tag(:ProductFormDetail, product.product_form_detail_onix_code)
332
+ end
333
+ end
334
+
335
+
336
+ # @hidden_tags RecordReference NotificationType ProductIdentifier TitleDetail PublishingDetail ProductComposition
337
+ # @title Zabezpieczenia e-booków
338
+ # <strong>&lt;EpubTechnicalProtection&gt;</strong> Określa typ zabezpieczenia stosowanego przy publikacji e-booka.<br/>
339
+ # <strong>&lt;ProductFormDetail&gt;</strong> zawiera format w jakim rozprowadzany jest e-book.
340
+ # Aktualnie może przyjąć wartości takie jak:
341
+ # #{Elibri::ONIX::Dict::Release_3_0::ProductFormDetail::ALL.map(&:name).to_sentence(:last_word_connector => ' lub ')}
342
+ def export_epub_details!(product)
343
+ return unless product.kind_of_ebook?
344
+ if product.epub_technical_protection
345
+ comment_dictionary "Zabezpieczenie", :EpubTechnicalProtection, :indent => 10, :kind => :onix_epub_details
346
+ tag(:EpubTechnicalProtection, product.epub_technical_protection_onix_code)
347
+ end
348
+ end
349
+
350
+
351
+ # @hidden_tags RecordReference NotificationType ProductIdentifier ProductComposition ProductForm TitleDetail
352
+ # @title Wymiary produktu
353
+ # Następujące atrybuty są udostępniane: wysokość, szerokość, grubość oraz masę produktu. Pierwsze trzy podajemy zawsze w milimetrach, masę w gramach.
354
+ # W przypadku map eksportujemy również jej skalę w tagu &lt;MapScale&gt;
355
+ def export_measurement!(product)
356
+ return unless product.kind_of_measurable?
357
+ [[product.height, Elibri::ONIX::Dict::Release_3_0::MeasureType::HEIGHT, Product::HEIGHT_UNIT, 'Wysokość'],
358
+ [product.width, Elibri::ONIX::Dict::Release_3_0::MeasureType::WIDTH, Product::WIDTH_UNIT, 'Szerokość'],
359
+ [product.thickness, Elibri::ONIX::Dict::Release_3_0::MeasureType::THICKNESS, Product::THICKNESS_UNIT, 'Grubość'],
360
+ [product.weight, Elibri::ONIX::Dict::Release_3_0::MeasureType::WEIGHT, Product::WEIGHT_UNIT, 'Masa']
361
+ ].each do |value, measure_type_code, unit_code, name|
362
+ if value
363
+ tag(:Measure) do
364
+ comment "#{name}: #{value}#{unit_code}", :kind => :onix_measurement
365
+ tag(:MeasureType, measure_type_code) #lista 48
366
+ tag(:Measurement, value)
367
+ tag(:MeasureUnitCode, unit_code)
368
+ end
369
+ end
370
+ end
371
+
372
+ if product.kind_of_map? and product.map_scale
373
+ comment 'Skala mapy - tylko dla produktów typu mapa'
374
+ tag(:MapScale, product.map_scale)
375
+ end
376
+ end
377
+
378
+
379
+ # @hidden_tags ProductIdentifier DescriptiveDetail ProductSupply
380
+ # @title Cykl życia rekordu
381
+ # W ONIX-ie status rekordu jest reprezentowany za pomocą kombinacji tagów <strong>&lt;NotificationType&gt;</strong> i <strong>&lt;PublishingStatus&gt;</strong>
382
+ #
383
+ #
384
+ # Tuż po założeniu przez wydawnictwo każdy rekord ma status prywatny. Jest to wtedy widoczny tylko i wyłącznie dla pracowników wydawnictwa,
385
+ # i nie jest udostępniany na zewnątrz. Po wypełnieniu kilku podstawowych danych (autor, tytuł) pracownik wydawnictwa może zmienić status
386
+ # rekordu na <i>zapowiedź</i>. W tym przypadku wartość <strong>&lt;NotificationType&gt;</strong> to 01 - wczesne powiadomienie.
387
+ #
388
+ # @render onix_announced_product_example
389
+ #
390
+ # Po uzupełnieniu większości danych niezbędnych (okładka, cena, ISBN, okładka, dokładna data premiery) wydawnictwo może zmienić
391
+ # status rekordu na <i>przedsprzedaż</i>.
392
+ # W zależności od naszego poziomu zaufania do terminowości wydawnictwa można uruchomić dla takiego tytułu przedsprzedaż na stronie księgarni.
393
+ # Wydawnictwo może zmienić datę premiery, jeśli produkt znajduje się w przedsprzedaży, warto zaimplementować procedurę poinformowania klientów
394
+ # o zmianie.
395
+ # Rekord o takim statusie ma wartość 02 w <strong>&lt;NotificationType&gt;</strong>
396
+ #
397
+ # @render onix_preorder_product_example
398
+ #
399
+ # Po ukazaniu się książki jej status zostaje zmieniony na <i>dostępna na rynku</i>.
400
+ # Rekord o takim statusie ma wartość 03 w <strong>&lt;NotificationType&gt;</strong> i 04 w <strong>&lt;PublishingDetail&gt;</strong>
401
+ #
402
+ # @render onix_published_product_example
403
+ #
404
+ # Każde wydawnictwo oczywiście liczy na to, że nakład książki się wyprzeda. Bardzo trudno jest poprawnie zdefiniować, co oznacza wyczerpany nakład.
405
+ # Bardzo długo egzemplarze książki, której nie ma już w magazynie wydawnictwa, mogą znajdować się w księgarniach i być zwracane co jakiś czas do hurtowni,
406
+ # co powoduje, że dany tytuł będzie się stawał na jakiś czas dostępny. W związku z tym informacje o wyczerpaniu się nakładu podejmuje wydawnictwo, i oznacza
407
+ # to, że nie będzie akceptować zamówień na określony tytuł. Nie oznacza to jednak, że tytuł jest w ogóle niedostępny, w dalszym ciągu może być w ofercie
408
+ # hurtowni.
409
+ # Rekord o statusie <i>nakład wyczerpany</i> ma wartość 03 w <strong>&lt;NotificationType&gt;</strong> i 07 w <strong>&lt;PublishingDetail&gt;</strong>
410
+ #
411
+ # @render onix_out_of_print_product_example
412
+ #
413
+ # Status 08 (niedostępny) w <strong>&lt;PublishingDetail&gt;</strong> nie jest w tej chwili używany przez eLibri. W przyszłości proszę się spodziewać również
414
+ # dodania informacji o dodrukach realizowanych pod tym samym numerem ISBN.
415
+ #
416
+ def export_publishing_status!(product)
417
+ if product.publishing_status_onix_code.present?
418
+ comment_dictionary 'Status publikacji', :PublishingStatusCode, :indent => 10, :kind => :onix_publishing_status
419
+ tag(:PublishingStatus, product.publishing_status_onix_code) #lista 64 #TODO sprawdzić
420
+ end
421
+
422
+ #TODO - tu można również zawrzeć datę, przed którą produkt nie może być importowany do baz sklepów
423
+ date, format_code = product.publication_date_with_onix_format_code
424
+ if date && format_code
425
+ tag(:PublishingDate) do
426
+ comment 'Zawsze 01 - data publikacji', :kind => :onix_publishing_status
427
+ tag(:PublishingDateRole, Elibri::ONIX::Dict::Release_3_0::PublishingDateRole::PUBLICATION_DATE) #lista 163
428
+ comment_dictionary "Format daty", :DateFormat, :indent => 12, :kind => :onix_publishing_status
429
+ tag(:DateFormat, format_code) #lista 55
430
+ tag(:Date, date)
431
+ end
432
+ end
433
+ end
434
+
435
+
436
+ # @hidden_tags RecordReference NotificationType ProductIdentifier DescriptiveDetail
437
+ # @title Ograniczenia sprzedaży
438
+ # eLibri umożliwia przechowywanie informacji o ograniczaniach dotyczących sprzedaży produktu.
439
+ # Obecnie obsługuje tylko 1 typ ograniczenia: wyłączność na produkt dla określonego detalisty.
440
+ # Opcjonalnie może się też pojawić data wygaśnięcia ograniczenia - w innym przypadku oznacza to, że produkt został przeznaczony tylko
441
+ # dla jednej, określonej sieci.
442
+ # W przypadku, gdy jest podana data wyłączności na sprzedaż produktu, należy ją traktować jako faktyczną datę premiery.
443
+ def export_sale_restrictions!(product)
444
+ if product.sale_restricted?
445
+ tag(:SalesRestriction) do
446
+ #lista 71 - For sale only through designated retailer, though not under retailer's own brand/imprint.
447
+ comment "Typ restrykcji - używamy tylko #{Elibri::ONIX::Dict::Release_3_0::SalesRestrictionType::RETAILER_EXCLUSIVE} (sprzedaż tylko poprzez wybranego detalistę)", :kind => :onix_sale_restrictions
448
+ tag(:SalesRestrictionType, Elibri::ONIX::Dict::Release_3_0::SalesRestrictionType::RETAILER_EXCLUSIVE)
449
+ tag(:SalesOutlet) do
450
+ tag(:SalesOutletName, product.sale_restricted_for)
451
+ end
452
+ comment "Ograniczenie wygasa #{product.sale_restricted_to.strftime("%d.%m.%Y")}", :kind => :onix_sale_restrictions
453
+ tag(:EndDate, product.sale_restricted_to.strftime("%Y%m%d"))
454
+ end
455
+ end
456
+ end
457
+
458
+
459
+ # @hidden_tags RecordReference NotificationType ProductIdentifier ProductComposition ProductForm TitleDetail
460
+ # @title Wiek czytelnika
461
+ # Zarówno wiek 'od', jak i wiek 'do' są opcjonalne.
462
+ def export_audience_range!(product)
463
+ if product.audience_age_from.present?
464
+ tag(:AudienceRange) do
465
+ comment "Ograniczenie dotyczy wieku czytelnika - zawsze #{Elibri::ONIX::Dict::Release_3_0::AudienceRangeQualifier::READING_AGE}", :kind => :onix_audience_range
466
+ tag(:AudienceRangeQualifier, Elibri::ONIX::Dict::Release_3_0::AudienceRangeQualifier::READING_AGE)
467
+ comment "Wiek od #{product.audience_age_from} lat", :kind => :onix_audience_range
468
+ tag(:AudienceRangePrecision, Elibri::ONIX::Dict::Release_3_0::AudienceRangePrecision::FROM)
469
+ tag(:AudienceRangeValue, product.audience_age_from)
470
+ end
471
+ end
472
+
473
+ if product.audience_age_to.present?
474
+ tag(:AudienceRange) do
475
+ comment "Ograniczenie dotyczy wieku czytelnika - zawsze #{Elibri::ONIX::Dict::Release_3_0::AudienceRangeQualifier::READING_AGE}", :kind => :onix_audience_range
476
+ tag(:AudienceRangeQualifier, Elibri::ONIX::Dict::Release_3_0::AudienceRangeQualifier::READING_AGE)
477
+ comment "Wiek do #{product.audience_age_to} lat", :kind => :onix_audience_range
478
+ tag(:AudienceRangePrecision, Elibri::ONIX::Dict::Release_3_0::AudienceRangePrecision::TO)
479
+ tag(:AudienceRangeValue, product.audience_age_to)
480
+ end
481
+ end
482
+ end
483
+
484
+
485
+ # @hidden_tags RecordReference NotificationType ProductIdentifier DescriptiveDetail
486
+ # @title Informacje o wydawcy
487
+ # W rekordzie znajduje się oczywiście nazwa wydawnictwa. Wydawca może określić też imprint.
488
+ # Z imprintem mamy do czynienia wtedy, gdy książki są wydawane pod różnymi markami, pula ISBN jest jednak wspólna.
489
+ # Jeśli wydawnictwo uzupełnia nazwę imprintu, to powinna być ona traktowana jako nazwa wydawnictwa przy prezentacji
490
+ # książki klientowi końcowemu.
491
+ def export_publisher_info!(product)
492
+ if product.imprint
493
+ tag(:Imprint) do
494
+ comment "Nazwa imprintu", :kind => :onix_publisher_info
495
+ tag(:ImprintName, product.imprint.name)
496
+ end
497
+ end
498
+
499
+ if product.publisher_name
500
+ tag(:Publisher) do
501
+ comment "Wydawca - używamy tylko kodu 01 (główny wydawca)", :kind => :onix_publisher_info
502
+ tag(:PublishingRole, '01') # Publisher, lista 45 #TODO jeszcze może być współwydawca
503
+ tag(:PublisherIdentifier) do
504
+ tag(:PublisherIDType, '01') #prioprietary
505
+ tag(:IDTypeName, 'ElibriPublisherCode')
506
+ tag(:IDValue, product.publisher_id)
507
+ end
508
+ tag(:PublisherName, product.publisher_name)
509
+ end
510
+ end
511
+ end
512
+
513
+
514
+ # @hidden_tags RecordReference NotificationType ProductIdentifier ProductComposition ProductForm TitleDetail
515
+ # @title Pozostałe atrybuty
516
+ # Dodatkowo każdy produkt może mieć kilka dodatkowych atrybutów: wielkość pliku (w Mb, tylko e-book),
517
+ # czas trwania (tylko audiobook, w minutach), ilość stron, ilość ilustracji.
518
+ #
519
+ # Poniżej przykład dla e-booka (wielkość pliku, ilość stron i ilustracji)
520
+ # @render onix_ebook_extent_example
521
+ #
522
+ # I przykład dla audiobook-a, z czasem trwania nagrania:
523
+ # @render onix_audiobook_extent_example
524
+ def export_extent!(product)
525
+ if product.kind_of_ebook? and product.file_size
526
+ tag(:Extent) do
527
+ comment 'Rozmiar pliku (w MB) - tylko dla produktów typu e-book', :kind => :onix_extent
528
+ tag(:ExtentType, Elibri::ONIX::Dict::Release_3_0::ExtentType::FILE_SIZE)
529
+ tag(:ExtentValue, product.file_size)
530
+ comment 'W MB', :kind => :onix_extent
531
+ tag(:ExtentUnit, Elibri::ONIX::Dict::Release_3_0::ExtentUnit::MEGABYTES)
532
+ end
533
+ end
534
+
535
+ if product.kind_of_audio? and product.duration
536
+ tag(:Extent) do
537
+ comment 'Czas trwania (w minutach) - tylko dla produktów typu audio', :kind => :onix_extent
538
+ tag(:ExtentType, Elibri::ONIX::Dict::Release_3_0::ExtentType::DURATION)
539
+ tag(:ExtentValue, product.duration)
540
+ comment 'W minutach', :kind => :onix_extent
541
+ tag(:ExtentUnit, Elibri::ONIX::Dict::Release_3_0::ExtentUnit::MINUTES)
542
+ end
543
+ end
544
+
545
+ if (product.kind_of_book? or product.kind_of_ebook?) && product.number_of_pages #number_of_pages to int
546
+ tag(:Extent) do
547
+ comment 'Liczba stron - tylko dla produktów typu książka', :kind => :onix_extent
548
+ tag(:ExtentType, Elibri::ONIX::Dict::Release_3_0::ExtentType::PAGE_COUNT)
549
+ tag(:ExtentValue, product.number_of_pages)
550
+ tag(:ExtentUnit, Elibri::ONIX::Dict::Release_3_0::ExtentUnit::PAGES)
551
+ end
552
+ end
553
+
554
+ if (product.kind_of_book? or product.kind_of_ebook?) and product.number_of_illustrations
555
+ comment 'Liczba ilustracji - tylko dla produktów typu książka', :kind => :onix_extent
556
+ tag(:NumberOfIllustrations, product.number_of_illustrations)
557
+ end
558
+ end
559
+
560
+ # @hidden_tags RecordReference NotificationType ProductIdentifier ProductComposition ProductForm TitleDetail
561
+ # @title Kategorie
562
+ # eLibri stosuje wewnętrzną hierarchę kategorii, dostępną w formacie JSON pod adresem
563
+ # = link_to product_categories_json_url, product_categories_json_url
564
+ def export_subjects!(product)
565
+ if product.elibri_product_categories.present? or product.publisher_product_categories.present?
566
+ comment 'Stosujemy wewnętrzną kategoryzację. Lista kategorii Elibri w formacie JSON: http://www.elibri.com.pl/assets/product_categories.js'
567
+ end
568
+
569
+ # Kategorie wg. eLibri
570
+ product.elibri_product_categories.each_with_index do |product_category,i|
571
+ tag(:Subject) do
572
+ tag(:MainSubject) if i.zero?
573
+ tag(:SubjectSchemeIdentifier, Elibri::ONIX::Dict::Release_3_0::SubjectSchemeIdentifier::PROPRIETARY)
574
+ tag(:SubjectSchemeName, 'elibri.com.pl')
575
+ tag(:SubjectSchemeVersion, '1.0')
576
+ tag(:SubjectCode, product_category.id)
577
+ tag(:SubjectHeadingText, product_category.full_node_path_name)
578
+ end
579
+ end
580
+
581
+ # Kategorie wg. wydawnictwa
582
+ product.publisher_product_categories.each do |product_category|
583
+ tag(:Subject) do
584
+ tag(:SubjectSchemeIdentifier, Elibri::ONIX::Dict::Release_3_0::SubjectSchemeIdentifier::PROPRIETARY)
585
+ tag(:SubjectSchemeName, product.publisher_name)
586
+ tag(:SubjectHeadingText, product_category.name)
587
+ end
588
+ end
589
+ end
590
+
591
+
592
+ # @hidden_tags RecordReference NotificationType ProductIdentifier ProductComposition ProductForm TitleDetail
593
+ # @title Autorzy, redaktorzy ...
594
+ # Każdy produkt może mieć wymienionych autorów, może być informacja, że jest to praca zbiorowa, produkt może nie mieć też żadnego autora (np. mapa)
595
+ #
596
+ #
597
+ # Każdy twórca ma przypisaną jedną z wielu ról (&lt;ContributorRole&gt;). W przypadku tłumacza dodawana jest informacja, z jakiego języka
598
+ # nastąpiło tłumaczenie (&lt;FromLanguage&gt;)
599
+ #
600
+ #
601
+ # W przypadku właściwego uzupełnienia danych w eLibri, system potrafi podzielić fragmenty personaliów
602
+ # autora i wyeksportować je w oddzielnych tagach ONIX. Rozróżniane są następujące fragmenty: tytuł naukowy (&lt;TitlesBeforeNames&gt;),
603
+ # imię (&lt;NamesBeforeKey&gt;), prefix nazwiska (von, van - &lt;PrefixToKey&gt;), nazwisko (&lt;KeyNames&gt;),
604
+ # postfix nazwiska (najczęściej określenie zakonu, np. OP - &lt;NamesAfterKey&gt;).
605
+ # Zawsze jest jednak exportowane pełne brzemienie imienia i nazwiska (&lt;PersonName&gt;)
606
+ #
607
+ #
608
+ # Zdarzają się również przypadki, gdzie wyżej podany podział nie jest albo znany, albo możliwy (np. św. Tomasz z Akwinu), wtedy
609
+ # exportowany jest tylko tag &lt;PersonName&gt;
610
+ #
611
+ # Jeśli wydawnictwo uzupełniło biogram autora, to jest on dostępny w tagu &lt;BiographicalNote&gt;
612
+ #
613
+ # @render onix_contributors_example
614
+ #
615
+ # W przypadku pracy zbiorowej rekord wygląda następująco:
616
+ #
617
+ # @render onix_collective_work_example
618
+ #
619
+ # Jeśli produkt nie ma żadnego autora, użyty zostaje tag &lt;NoContributor&gt;
620
+ #
621
+ # @render onix_no_contributors_example
622
+ #
623
+ #
624
+ def export_contributors!(product)
625
+ if product.authorship_kind.user_given?
626
+ comment 'Gdy wyszczególniono autorów', :kind => :onix_contributors if product.contributors.present?
627
+ product.contributors.each_with_index do |contributor, idx|
628
+ tag(:Contributor, :sourcename => "contributorid:#{contributor.id}", :datestamp => contributor.updated_at.to_s(:onix)) do
629
+ tag(:SequenceNumber, idx + 1)
630
+ comment_dictionary 'Rola autora', :ContributorRole, :indent => 10, :kind => :onix_contributors
631
+ tag(:ContributorRole, contributor.role_onix_code) #lista 17
632
+ comment 'Tylko w przypadku tłumaczy:', :kind => :onix_contributors
633
+ tag(:FromLanguage, contributor.language_onix_code) if contributor.language_onix_code
634
+ tag(:PersonName, contributor.generated_full_name) #zawsze jest TODO - dodać takie pole do bazy danych
635
+
636
+ tag(:TitlesBeforeNames, contributor.title) if contributor.title.present? #tytuł
637
+ tag(:NamesBeforeKey, contributor.name) if contributor.name.present? #imię
638
+ tag(:PrefixToKey, contributor.last_name_prefix) if contributor.last_name_prefix.present? #van, von
639
+ tag(:KeyNames, contributor.last_name) if contributor.last_name.present?
640
+ tag(:NamesAfterKey, contributor.last_name_postfix) if contributor.last_name_postfix.present?
641
+ tag(:BiographicalNote, contributor.biography.text) if contributor.biography
642
+ end
643
+ end
644
+ end
645
+
646
+ if product.authorship_kind.collective?
647
+ comment 'Gdy jest to praca zbiorowa', :kind => :onix_contributors
648
+ tag(:Contributor) do
649
+ comment "Autor - #{Elibri::ONIX::Dict::Release_3_0::ContributorRole::AUTHOR}", :kind => :onix_contributors
650
+ tag(:ContributorRole, Elibri::ONIX::Dict::Release_3_0::ContributorRole::AUTHOR)
651
+ comment "Różne osoby - #{Elibri::ONIX::Dict::Release_3_0::UnnamedPersons::VARIOUS_AUTHORS}", :kind => :onix_contributors
652
+ tag(:UnnamedPersons, Elibri::ONIX::Dict::Release_3_0::UnnamedPersons::VARIOUS_AUTHORS)
653
+ end
654
+ end
655
+
656
+ if product.authorship_kind.no_contributor?
657
+ comment 'Gdy brak autorów', :kind => :onix_contributors
658
+ tag(:NoContributor)
659
+ end
660
+ end
661
+
662
+ # @hidden_tags RecordReference NotificationType ProductIdentifier ProductComposition ProductForm
663
+ # @title Tytuły
664
+ # W dokumencie XML mogą pojawić się 3 typy tytułu: pełen tytuł produktu, tytuł w języku oryginału (jeśli jest tłumaczeniem)
665
+ # oraz roboczy tytuł nadany przez wydawcę.
666
+ # @render onix_titles_example
667
+ #
668
+ # Tytuł może być też kaskadowy. Dobrym przykładem jest na przykład Thorgal, komiks, który ma wiele tomów, każdy tom ma swój numer, jak i tytuł.
669
+ # W kategoriach ONIX-a Thorgal jest kolekcją. Od serii odróżnia go to, że jest częścią tytułu. Innym dobrym przykładem jest książka "Gra o Tron",
670
+ # która należy do kolekcji "Pieśń Lodu i Ognia" - ponieważ jest to częścią tytułu.
671
+ # @render onix_title_with_collection_example
672
+ #
673
+ #
674
+ def export_titles!(product)
675
+ if product.title_parts.present? or product.or_title.present? or product.trade_title.present?
676
+ #comment_dictionary 'Rozróżniane typy tytułów', :TitleType, :indent => 10, :kind => :onix_titles
677
+ end
678
+
679
+ if product.title_parts.present?
680
+ tag(:TitleDetail) do
681
+ comment "Pełen tytuł produktu - #{Elibri::ONIX::Dict::Release_3_0::TitleType::DISTINCTIVE_TITLE}", :kind => :onix_titles
682
+ tag(:TitleType, Elibri::ONIX::Dict::Release_3_0::TitleType::DISTINCTIVE_TITLE)
683
+ product.title_parts.each do |title_part|
684
+ tag(:TitleElement) do
685
+ if title_part.level == Elibri::ONIX::Dict::Release_3_0::TitleElementLevel::PRODUCT
686
+ comment "Tytuł na poziomie produktu - #{Elibri::ONIX::Dict::Release_3_0::TitleElementLevel::PRODUCT}", :kind => :onix_titles
687
+ elsif title_part.level == Elibri::ONIX::Dict::Release_3_0::TitleElementLevel::COLLECTION
688
+ comment "Tytuł na poziomie kolekcji - #{Elibri::ONIX::Dict::Release_3_0::TitleElementLevel::COLLECTION}", :kind => :onix_titles
689
+ end
690
+ tag(:TitleElementLevel, title_part.level) #odnosi się do tego produktu tylko
691
+ tag(:PartNumber, title_part.part) if title_part.part.present?
692
+ tag(:TitleText, title_part.title) if title_part.title.present?
693
+ tag(:Subtitle, title_part.subtitle) if title_part.subtitle.present?
694
+ end
695
+ end
696
+ end
697
+ end
698
+ if product.or_title.present?
699
+ tag(:TitleDetail) do
700
+ comment "Tytuł w języku oryginału - #{Elibri::ONIX::Dict::Release_3_0::TitleType::DISTINCTIVE_TITLE}", :kind => :onix_titles
701
+ tag(:TitleType, Elibri::ONIX::Dict::Release_3_0::TitleType::ORIGINAL_TITLE)
702
+ tag(:TitleElement) do
703
+ comment "Tytuł na poziomie produktu - #{Elibri::ONIX::Dict::Release_3_0::TitleElementLevel::PRODUCT}", :kind => :onix_titles
704
+ tag(:TitleElementLevel, Elibri::ONIX::Dict::Release_3_0::TitleElementLevel::PRODUCT)
705
+ tag(:TitleText, product.or_title)
706
+ end
707
+ end
708
+ end
709
+ if product.trade_title.present?
710
+ tag(:TitleDetail) do
711
+ comment "Tytuł handlowy używany przez wydawnictwo - #{Elibri::ONIX::Dict::Release_3_0::TitleType::DISTRIBUTORS_TITLE}", :kind => :onix_titles
712
+ tag(:TitleType, Elibri::ONIX::Dict::Release_3_0::TitleType::DISTRIBUTORS_TITLE) #tytuł produktu
713
+ tag(:TitleElement) do
714
+ comment "Tytuł na poziomie produktu - #{Elibri::ONIX::Dict::Release_3_0::TitleElementLevel::PRODUCT}", :kind => :onix_titles
715
+ tag(:TitleElementLevel, Elibri::ONIX::Dict::Release_3_0::TitleElementLevel::PRODUCT)
716
+ tag(:TitleText, product.trade_title)
717
+ end
718
+ end
719
+ end
720
+ end
721
+
722
+
723
+ # @hidden_tags RecordReference NotificationType ProductIdentifier ProductComposition ProductForm TitleDetail
724
+ # @title Opis wydania
725
+ def export_edition!(product)
726
+ if product.edition_statement.present?
727
+ comment 'Opis wydania', :kind => :onix_edition
728
+ tag(:EditionStatement, product.edition_statement)
729
+ end
730
+ end
731
+
732
+
733
+ # @hidden_tags RecordReference NotificationType ProductIdentifier ProductComposition ProductForm TitleDetail
734
+ # @title Języki
735
+ # Języki, w których dostępny jest produkt.
736
+ def export_languages!(product)
737
+ comment_dictionary 'Rola języka', :LanguageRole, :indent => 10, :kind => :onix_languages if product.languages.present?
738
+ product.languages.each do |language|
739
+ tag(:Language) do
740
+ tag(:LanguageRole, language.role_onix_code) #lista 22
741
+ tag(:LanguageCode, language.language_onix_code) #lista 74
742
+ end
743
+ end
744
+ end
745
+
746
+
747
+ # @hidden_tags RecordReference NotificationType ProductIdentifier DescriptiveDetail
748
+ # @title Teksty
749
+ # Wydawca może wprowadzić do eLibri różne informacje tekstowe - opis produktu, spis treści, recenzję (jeśli ma prawa ją udostępnić), jak i fragment książki.
750
+ # Biogramy autorów są udostępniane wraz z informacjami o
751
+ # = link_to "autorach", doc_api_path("onix_contributors")
752
+ def export_texts!(product)
753
+ comment_dictionary 'Typy tekstów', :OtherTextType, :indent => 10, :kind => :onix_texts if product.other_texts.present?
754
+ product.other_texts.each do |other_text|
755
+ #jeśli jest pusty tekst, nie nadaje się do umieszczania w ONIX albo tekst dotyczy autora (type_onix_code.blank?) -> nie exportuj
756
+ next if other_text.text.blank? || other_text.type_onix_code.blank? || !other_text.exportable?
757
+
758
+ tag(:TextContent, :sourcename => "textid:#{other_text.id}", :datestamp => other_text.updated_at.to_s(:onix)) do
759
+ tag(:TextType, other_text.type_onix_code) #lista 153
760
+ comment "Zawsze #{Elibri::ONIX::Dict::Release_3_0::ContentAudience::UNRESTRICTED} - Unrestricted", :kind => :onix_texts
761
+ tag(:ContentAudience, Elibri::ONIX::Dict::Release_3_0::ContentAudience::UNRESTRICTED)
762
+
763
+ if other_text.is_a_review? && other_text.resource_link.present?
764
+ text_source = {:sourcename => other_text.resource_link}
765
+ else
766
+ text_source = {}
767
+ end
768
+
769
+ tag(:Text, text_source) do |builder|
770
+ builder.cdata!(other_text.text)
771
+ end
772
+
773
+ tag(:TextAuthor, other_text.text_author) if other_text.text_author.present?
774
+ tag(:SourceTitle, other_text.source_title) if other_text.source_title.present?
775
+ end
776
+ end
777
+ end
778
+
779
+
780
+ # @hidden_tags RecordReference NotificationType ProductIdentifier DescriptiveDetail
781
+ # @title Załączniki
782
+ # Wydawca może załączyć do każdego produktu dowolną liczbę plików - a przynajmniej jeden, okładkę. Proszę za każdym razem
783
+ # tworzyć kopię pliku na swoim serwerze, hotlinking jest niedozwolony.
784
+ def export_supporting_resources!(product)
785
+ product.attachments.each do |attachment|
786
+ if attachment.onix_resource_mode #jeśli klient coś dzikiego wgrał, to ignoruj to
787
+ tag(:SupportingResource, :sourcename => "resourceid:#{attachment.id}", :datestamp => attachment.updated_at.to_s(:onix)) do
788
+ comment_dictionary 'Typ załącznika', :ResourceContentType, :indent => 12, :kind => :onix_supporting_resources
789
+ tag(:ResourceContentType, attachment.attachment_type_code) #lista 158
790
+ comment 'Zawsze 00 - Unrestricted', :kind => :onix_supporting_resources
791
+ tag(:ContentAudience, Elibri::ONIX::Dict::Release_3_0::ContentAudience::UNRESTRICTED)
792
+ comment_dictionary 'Rodzaj załącznika', :ResourceMode, :indent => 12, :kind => :onix_supporting_resources
793
+ tag(:ResourceMode, attachment.onix_resource_mode) #lista 159
794
+ tag(:ResourceVersion) do
795
+ comment 'Zawsze 02 - Downloadable file', :kind => :onix_supporting_resources
796
+ tag(:ResourceForm, Elibri::ONIX::Dict::Release_3_0::ResourceForm::DOWNLOADABLE_FILE)
797
+ url = attachment.file.url
798
+ if url.index("http://") #w sklepie zwraca mi całego linka, wygodniej mi jest to tutaj wychwycić
799
+ tag(:ResourceLink, URI.escape(url))
800
+ else
801
+ tag(:ResourceLink, URI.escape('http://' + HOST_NAME + url))
802
+ end
803
+ end
804
+ end
805
+ end
806
+ end
807
+ end
808
+
809
+
810
+ # @hidden_tags RecordReference NotificationType ProductIdentifier ProductComposition ProductForm
811
+ # @title Serie wydawnicze
812
+ # Serie wydawnicze są opisywane w podobny sposób co tytuł, zawarte są jednak w tagu <strong>&lt;Collection&gt;</strong>
813
+ # Struktura jest dosyć zawiła, ale wszystkie wartości są sztywne, więc nie powinno być problemu z odczytaniem informacji.
814
+ # Oprócz nazwy serii może zostać również podany numer wewnątrz serii, jeśli seria jest numerowana.
815
+ # Książka może należeć do kilku serii, wtedy tag <strong>&lt;Collection&gt;</strong> występuje kilkukrotnie.
816
+ def export_series_memberships!(product)
817
+ if product.series_membership_kind.user_given?
818
+ product.series_memberships.each_with_index do |series_membership, idx|
819
+ tag(:Collection) do
820
+ comment "Używamy tylko #{Elibri::ONIX::Dict::Release_3_0::CollectionType::PUBLISHER_COLLECTION} - seria wydawnictwa", :kind => :onix_series_memberships
821
+ tag(:CollectionType, Elibri::ONIX::Dict::Release_3_0::CollectionType::PUBLISHER_COLLECTION) #lista 148
822
+ comment "Teraz następuje podobna struktura, jak w przypadku tytułu", :kind => :onix_series_memberships
823
+ tag(:TitleDetail) do
824
+ comment "Używamy tylko #{Elibri::ONIX::Dict::Release_3_0::TitleType::DISTINCTIVE_TITLE}", :kind => :onix_series_memberships
825
+ tag(:TitleType, Elibri::ONIX::Dict::Release_3_0::TitleType::DISTINCTIVE_TITLE)
826
+ tag(:TitleElement) do
827
+ comment "Używamy tylko #{Elibri::ONIX::Dict::Release_3_0::TitleElementLevel::COLLECTION}", :kind => :onix_series_memberships
828
+ tag(:TitleElementLevel, Elibri::ONIX::Dict::Release_3_0::TitleElementLevel::COLLECTION)
829
+ tag(:PartNumber, series_membership.number_within_series) if series_membership.number_within_series.present?
830
+ tag(:TitleText, series_membership.series_name)
831
+ end
832
+ end
833
+ end
834
+ end
835
+ end
836
+ end
837
+
838
+
839
+ # @hidden_tags RecordReference NotificationType ProductIdentifier DescriptiveDetail
840
+ # @title Powiązane produkty
841
+ def export_related_products!(product)
842
+ tag(:RelatedMaterial) do
843
+
844
+ comment_dictionary "Typy relacji", :ProductRelationType, :indent => 10, :kind => :onix_related_products
845
+ product.facsimiles.each do |facsimile|
846
+ tag(:RelatedProduct) do
847
+ tag(:ProductRelationCode, Elibri::ONIX::Dict::Release_3_0::ProductRelationType::FACSIMILES)
848
+ tag(:ProductIdentifier) do
849
+ comment "Zawsze #{Elibri::ONIX::Dict::Release_3_0::ProductIDType::PROPRIETARY} - symbol wydawcy", :kind => :onix_related_products
850
+ tag(:ProductIDType, Elibri::ONIX::Dict::Release_3_0::ProductIDType::PROPRIETARY)
851
+ tag(:IDTypeName, facsimile.publisher_name)
852
+ tag(:IDValue, facsimile.publisher_symbol)
853
+ end
854
+
855
+ if facsimile.isbn_value.present?
856
+ tag(:ProductIdentifier) do
857
+ comment 'Zawsze ISBN-13'
858
+ tag(:ProductIDType, Elibri::ONIX::Dict::Release_3_0::ProductIDType::ISBN13)
859
+ tag(:IDValue, facsimile.isbn_value)
860
+ end
861
+ end
862
+ end
863
+ end
864
+
865
+ # Nie powtarzaj w zbiorze produktów podobnych faksymili:
866
+ (product.similar_products - product.facsimiles).each do |similar_product|
867
+ tag(:RelatedProduct) do
868
+ tag(:ProductRelationCode, Elibri::ONIX::Dict::Release_3_0::ProductRelationType::SIMILAR_PRODUCTS)
869
+ tag(:ProductIdentifier) do
870
+ comment "Zawsze #{Elibri::ONIX::Dict::Release_3_0::ProductIDType::PROPRIETARY} - symbol wydawcy"
871
+ tag(:ProductIDType, Elibri::ONIX::Dict::Release_3_0::ProductIDType::PROPRIETARY)
872
+ tag(:IDTypeName, similar_product.publisher_name)
873
+ tag(:IDValue, similar_product.publisher_symbol)
874
+ end
875
+
876
+ if similar_product.isbn_value.present?
877
+ tag(:ProductIdentifier) do
878
+ tag(:ProductIDType, Elibri::ONIX::Dict::Release_3_0::ProductIDType::ISBN13)
879
+ tag(:IDValue, similar_product.isbn_value)
880
+ end
881
+ end
882
+ end
883
+ end
884
+
885
+ end
886
+ end
887
+
888
+
889
+ # @hidden_tags RecordReference NotificationType DescriptiveDetail Supplier ProductAvailability Price
890
+ # @title Stany magazynowe
891
+ # Tag <strong>&lt;Stock&gt;</strong> może zawierać konkretną ilość produktu w <strong>&ltOnHand&gt;</strong>,
892
+ # lub słownie określoną ilość w <strong>&lt;StockQuantityCoded&gt;</strong>.<br/><br/>
893
+ # Dokument XML zawierający dane o stanach magazynowych produktu najczęściej zawiera także rozszerzoną listę
894
+ # identyfikatorów produktu. Poza podstawowym <strong>&lt;ProductIdentifier&gt;</strong>, znajdują się także identyfikatory
895
+ # poszczególnych dostawców. Tag <strong>&lt;IDTypeName&gt;</strong> zawiera nazwę dostawcy.
896
+ def export_supply_details!(product)
897
+ return if product.try(:skip_ProductSupply)
898
+ unless product.product_availabilities.empty?
899
+ tag(:ProductSupply) do
900
+ product.product_availabilities.each do |pa|
901
+ tag(:SupplyDetail) do
902
+ tag(:Supplier) do
903
+ comment_dictionary "Rola dostawcy", :SupplierRole, :indent => 12
904
+ tag(:SupplierRole, pa.supplier_role_onix_code) #lista 93
905
+ tag(:SupplierIdentifier) do
906
+ comment "Zawsze 02 - Proprietary. Identyfikujemy dostawcę po NIP"
907
+ tag(:SupplierIDType, '02') #lista 92, Proprietary
908
+ tag(:IDTypeName, 'NIP')
909
+ tag(:IDValue, pa.supplier.nip.gsub("-", ""))
910
+ end
911
+ tag(:SupplierName, pa.supplier.name)
912
+ tag(:TelephoneNumber, pa.supplier.phone) if pa.supplier.phone.present?
913
+ tag(:EmailAddress, pa.supplier.email) if pa.supplier.email.present?
914
+ if pa.supplier.website.present?
915
+ tag(:Website) do
916
+ tag(:WebsiteLink, pa.supplier.website)
917
+ end
918
+ end
919
+ end
920
+
921
+ comment_dictionary "Typ dostępności", :ProductAvailabilityType, :indent => 10
922
+ tag(:ProductAvailability, pa.product_availability_onix_code) #lista 65
923
+ if pa.stock_info
924
+ tag(:Stock) do
925
+ if pa.stock_info.exact_info?
926
+ tag(:OnHand, pa.stock_info.on_hand)
927
+ else
928
+ comment 'Nie znamy konkretnej ilości produktów na stanie'
929
+ tag(:StockQuantityCoded) do
930
+ comment 'Zawsze 01 - Proprietary'
931
+ tag(:StockQuantityCodeType, '01') #lista 70 - proprietary
932
+ tag(:StockQuantityCode, pa.stock_info.quantity_code) #low/high
933
+ end
934
+ end
935
+ end
936
+ end
937
+ if product.pack_quantity.present?
938
+ comment 'Ile produktów dostawca umieszcza w paczce'
939
+ tag(:PackQuantity, product.pack_quantity)
940
+ end
941
+
942
+ pa.price_infos.each do |price_info|
943
+ tag(:Price) do
944
+ comment_dictionary "Typ ceny", :PriceTypeCode, :indent => 12
945
+ tag(:PriceType, Elibri::ONIX::Dict::Release_3_0::PriceTypeCode::RRP_WITH_TAX) #lista 58
946
+ tag(:MinimumOrderQuantity, price_info.minimum_order_quantity) if price_info.minimum_order_quantity
947
+ tag(:PriceAmount, price_info.amount)
948
+ tag(:Tax) do
949
+ comment 'VAT'
950
+ tag(:TaxType, '01') #lista 174, VAT
951
+ tag(:TaxRatePercent, price_info.vat)
952
+ end
953
+ tag(:CurrencyCode, price_info.currency_code)
954
+ if product.price_printed_on_product_onix_code.present?
955
+ comment_dictionary "Cena na okładce?", :PricePrintedOnProduct, :indent => 12
956
+ tag(:PrintedOnProduct, product.price_printed_on_product_onix_code) #lista 174
957
+ comment 'Zawsze 00 - Unknown / unspecified'
958
+ tag(:PositionOnProduct, '00') #lista 142 - Position unknown or unspecified
959
+ end
960
+ end
961
+ end
962
+ end
963
+ end
964
+ end
965
+ end
966
+ end
967
+
968
+
969
+ # @title Rozszerzenia eLibri dla ONIX
970
+ # @hidden_tags RecordReference NotificationType ProductIdentifier DescriptiveDetail
971
+ # Standard ONIX nie przewiduje w chwili obecnej atrybutów produktów niezbędnych z punktu widzenia polskiego rynku wydawniczego.
972
+ # Są to atrybuty takie jak np. Vat czy PKWiU. eLibri rozszerza więc ONIX o kilka użytecznych tagów, wprowadzając nową przestrzeń nazw
973
+ # w generowanych XML`ach.
974
+ def export_elibri_extensions!(product)
975
+ if @elibri_onix_dialect >= '3.0.1'
976
+
977
+ if product.cover_type
978
+ comment_dictionary "Format okładki", Product::CoverType.all.map(&:name), :indent => 10
979
+ tag("elibri:CoverType", product.cover_type.name)
980
+ end
981
+
982
+ comment 'Cena na okładce'
983
+ tag("elibri:CoverPrice", product.price_amount) if product.price_amount.present?
984
+ comment 'Vat w procentach'
985
+ tag("elibri:Vat", product.vat) if product.vat.present?
986
+ tag("elibri:PKWiU", product.pkwiu) if product.pkwiu.present?
987
+ tag("elibri:preview_exists", product.preview_exists?.to_s)
988
+ end
989
+ end
990
+
991
+ end
992
+
993
+ end
994
+
995
+ end