elibri_onix_mocks 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/.travis.yml +10 -0
- data/Gemfile +4 -0
- data/README.md +32 -0
- data/Rakefile +8 -0
- data/elibri_onix_mocks.gemspec +32 -0
- data/lib/elibri_onix_mocks.rb +14 -0
- data/lib/elibri_onix_mocks/generators/xml_generator.rb +995 -0
- data/lib/elibri_onix_mocks/generators/xml_tags.yml +388 -0
- data/lib/elibri_onix_mocks/mocks/mock_method_missing.rb +91 -0
- data/lib/elibri_onix_mocks/mocks/xml_mocks.rb +801 -0
- data/lib/elibri_onix_mocks/onix_helpers.rb +160 -0
- data/lib/elibri_onix_mocks/version.rb +3 -0
- data/lib/elibri_onix_mocks/xml_variant.rb +122 -0
- data/spec/elibri_onix_mocks_spec.rb +33 -0
- data/spec/spec_helper.rb +12 -0
- metadata +179 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -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 :))
|
data/Rakefile
ADDED
@@ -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 <MapScale>
|
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><ProductIdentifier></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><ProductForm></strong> określa typ produktu. Np. BA to książka.<br/>
|
317
|
+
# <strong><ProductComposition></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><EpubTechnicalProtection></strong> Określa typ zabezpieczenia stosowanego przy publikacji e-booka.<br/>
|
339
|
+
# <strong><ProductFormDetail></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 <MapScale>
|
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><NotificationType></strong> i <strong><PublishingStatus></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><NotificationType></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><NotificationType></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><NotificationType></strong> i 04 w <strong><PublishingDetail></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><NotificationType></strong> i 07 w <strong><PublishingDetail></strong>
|
410
|
+
#
|
411
|
+
# @render onix_out_of_print_product_example
|
412
|
+
#
|
413
|
+
# Status 08 (niedostępny) w <strong><PublishingDetail></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 (<ContributorRole>). W przypadku tłumacza dodawana jest informacja, z jakiego języka
|
598
|
+
# nastąpiło tłumaczenie (<FromLanguage>)
|
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 (<TitlesBeforeNames>),
|
603
|
+
# imię (<NamesBeforeKey>), prefix nazwiska (von, van - <PrefixToKey>), nazwisko (<KeyNames>),
|
604
|
+
# postfix nazwiska (najczęściej określenie zakonu, np. OP - <NamesAfterKey>).
|
605
|
+
# Zawsze jest jednak exportowane pełne brzemienie imienia i nazwiska (<PersonName>)
|
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 <PersonName>
|
610
|
+
#
|
611
|
+
# Jeśli wydawnictwo uzupełniło biogram autora, to jest on dostępny w tagu <BiographicalNote>
|
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 <NoContributor>
|
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><Collection></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><Collection></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><Stock></strong> może zawierać konkretną ilość produktu w <strong><OnHand></strong>,
|
892
|
+
# lub słownie określoną ilość w <strong><StockQuantityCoded></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><ProductIdentifier></strong>, znajdują się także identyfikatory
|
895
|
+
# poszczególnych dostawców. Tag <strong><IDTypeName></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
|