im_onix 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (346) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +39 -0
  3. data/bin/html_codelist_to_yml.rb +46 -0
  4. data/bin/onix3_to_onix2.rb +192 -0
  5. data/bin/onix3_to_onix3.rb +401 -0
  6. data/bin/onix_bench.rb +15 -0
  7. data/bin/onix_pp.rb +216 -0
  8. data/bin/onix_split.rb +72 -0
  9. data/data/codelists/codelist-1.yml +12 -0
  10. data/data/codelists/codelist-10.yml +51 -0
  11. data/data/codelists/codelist-100.yml +8 -0
  12. data/data/codelists/codelist-101.yml +7 -0
  13. data/data/codelists/codelist-102.yml +5 -0
  14. data/data/codelists/codelist-11.yml +13 -0
  15. data/data/codelists/codelist-12.yml +15 -0
  16. data/data/codelists/codelist-121.yml +162 -0
  17. data/data/codelists/codelist-13.yml +10 -0
  18. data/data/codelists/codelist-138.yml +8 -0
  19. data/data/codelists/codelist-139.yml +102 -0
  20. data/data/codelists/codelist-14.yml +6 -0
  21. data/data/codelists/codelist-140.yml +9 -0
  22. data/data/codelists/codelist-141.yml +12 -0
  23. data/data/codelists/codelist-142.yml +14 -0
  24. data/data/codelists/codelist-143.yml +9 -0
  25. data/data/codelists/codelist-144.yml +10 -0
  26. data/data/codelists/codelist-145.yml +9 -0
  27. data/data/codelists/codelist-146.yml +5 -0
  28. data/data/codelists/codelist-147.yml +16 -0
  29. data/data/codelists/codelist-148.yml +6 -0
  30. data/data/codelists/codelist-149.yml +7 -0
  31. data/data/codelists/codelist-15.yml +15 -0
  32. data/data/codelists/codelist-150.yml +128 -0
  33. data/data/codelists/codelist-151.yml +10 -0
  34. data/data/codelists/codelist-152.yml +4 -0
  35. data/data/codelists/codelist-153.yml +19 -0
  36. data/data/codelists/codelist-154.yml +11 -0
  37. data/data/codelists/codelist-155.yml +10 -0
  38. data/data/codelists/codelist-156.yml +6 -0
  39. data/data/codelists/codelist-157.yml +6 -0
  40. data/data/codelists/codelist-158.yml +32 -0
  41. data/data/codelists/codelist-159.yml +8 -0
  42. data/data/codelists/codelist-16.yml +8 -0
  43. data/data/codelists/codelist-160.yml +6 -0
  44. data/data/codelists/codelist-161.yml +5 -0
  45. data/data/codelists/codelist-162.yml +9 -0
  46. data/data/codelists/codelist-163.yml +18 -0
  47. data/data/codelists/codelist-164.yml +7 -0
  48. data/data/codelists/codelist-165.yml +6 -0
  49. data/data/codelists/codelist-166.yml +6 -0
  50. data/data/codelists/codelist-167.yml +7 -0
  51. data/data/codelists/codelist-168.yml +4 -0
  52. data/data/codelists/codelist-169.yml +7 -0
  53. data/data/codelists/codelist-17.yml +95 -0
  54. data/data/codelists/codelist-170.yml +2 -0
  55. data/data/codelists/codelist-171.yml +4 -0
  56. data/data/codelists/codelist-172.yml +3 -0
  57. data/data/codelists/codelist-173.yml +5 -0
  58. data/data/codelists/codelist-174.yml +4 -0
  59. data/data/codelists/codelist-175.yml +217 -0
  60. data/data/codelists/codelist-176.yml +16 -0
  61. data/data/codelists/codelist-177.yml +4 -0
  62. data/data/codelists/codelist-178.yml +30 -0
  63. data/data/codelists/codelist-179.yml +4 -0
  64. data/data/codelists/codelist-18.yml +8 -0
  65. data/data/codelists/codelist-184.yml +10 -0
  66. data/data/codelists/codelist-19.yml +9 -0
  67. data/data/codelists/codelist-196.yml +22 -0
  68. data/data/codelists/codelist-197.yml +7 -0
  69. data/data/codelists/codelist-198.yml +4 -0
  70. data/data/codelists/codelist-2.yml +8 -0
  71. data/data/codelists/codelist-20.yml +2 -0
  72. data/data/codelists/codelist-203.yml +10 -0
  73. data/data/codelists/codelist-204.yml +6 -0
  74. data/data/codelists/codelist-21.yml +36 -0
  75. data/data/codelists/codelist-22.yml +11 -0
  76. data/data/codelists/codelist-23.yml +17 -0
  77. data/data/codelists/codelist-24.yml +13 -0
  78. data/data/codelists/codelist-25.yml +31 -0
  79. data/data/codelists/codelist-26.yml +94 -0
  80. data/data/codelists/codelist-27.yml +101 -0
  81. data/data/codelists/codelist-28.yml +10 -0
  82. data/data/codelists/codelist-29.yml +26 -0
  83. data/data/codelists/codelist-3.yml +13 -0
  84. data/data/codelists/codelist-30.yml +19 -0
  85. data/data/codelists/codelist-31.yml +5 -0
  86. data/data/codelists/codelist-32.yml +5 -0
  87. data/data/codelists/codelist-33.yml +44 -0
  88. data/data/codelists/codelist-34.yml +18 -0
  89. data/data/codelists/codelist-35.yml +8 -0
  90. data/data/codelists/codelist-36.yml +5 -0
  91. data/data/codelists/codelist-37.yml +8 -0
  92. data/data/codelists/codelist-38.yml +42 -0
  93. data/data/codelists/codelist-39.yml +21 -0
  94. data/data/codelists/codelist-40.yml +8 -0
  95. data/data/codelists/codelist-41.yml +8 -0
  96. data/data/codelists/codelist-42.yml +18 -0
  97. data/data/codelists/codelist-43.yml +8 -0
  98. data/data/codelists/codelist-44.yml +22 -0
  99. data/data/codelists/codelist-45.yml +15 -0
  100. data/data/codelists/codelist-46.yml +11 -0
  101. data/data/codelists/codelist-47.yml +6 -0
  102. data/data/codelists/codelist-48.yml +13 -0
  103. data/data/codelists/codelist-49.yml +87 -0
  104. data/data/codelists/codelist-5.yml +20 -0
  105. data/data/codelists/codelist-50.yml +10 -0
  106. data/data/codelists/codelist-51.yml +37 -0
  107. data/data/codelists/codelist-52.yml +3 -0
  108. data/data/codelists/codelist-53.yml +7 -0
  109. data/data/codelists/codelist-54.yml +25 -0
  110. data/data/codelists/codelist-55.yml +21 -0
  111. data/data/codelists/codelist-56.yml +4 -0
  112. data/data/codelists/codelist-57.yml +7 -0
  113. data/data/codelists/codelist-58.yml +27 -0
  114. data/data/codelists/codelist-59.yml +12 -0
  115. data/data/codelists/codelist-6.yml +78 -0
  116. data/data/codelists/codelist-60.yml +4 -0
  117. data/data/codelists/codelist-61.yml +5 -0
  118. data/data/codelists/codelist-62.yml +7 -0
  119. data/data/codelists/codelist-63.yml +2 -0
  120. data/data/codelists/codelist-64.yml +18 -0
  121. data/data/codelists/codelist-65.yml +31 -0
  122. data/data/codelists/codelist-66.yml +6 -0
  123. data/data/codelists/codelist-67.yml +4 -0
  124. data/data/codelists/codelist-68.yml +19 -0
  125. data/data/codelists/codelist-69.yml +6 -0
  126. data/data/codelists/codelist-7.yml +128 -0
  127. data/data/codelists/codelist-70.yml +4 -0
  128. data/data/codelists/codelist-71.yml +13 -0
  129. data/data/codelists/codelist-72.yml +9 -0
  130. data/data/codelists/codelist-73.yml +43 -0
  131. data/data/codelists/codelist-74.yml +491 -0
  132. data/data/codelists/codelist-75.yml +4 -0
  133. data/data/codelists/codelist-76.yml +14 -0
  134. data/data/codelists/codelist-77.yml +21 -0
  135. data/data/codelists/codelist-78.yml +179 -0
  136. data/data/codelists/codelist-79.yml +25 -0
  137. data/data/codelists/codelist-8.yml +9 -0
  138. data/data/codelists/codelist-80.yml +23 -0
  139. data/data/codelists/codelist-81.yml +41 -0
  140. data/data/codelists/codelist-82.yml +19 -0
  141. data/data/codelists/codelist-83.yml +71 -0
  142. data/data/codelists/codelist-84.yml +12 -0
  143. data/data/codelists/codelist-85.yml +25 -0
  144. data/data/codelists/codelist-86.yml +7 -0
  145. data/data/codelists/codelist-87.yml +8 -0
  146. data/data/codelists/codelist-88.yml +2 -0
  147. data/data/codelists/codelist-89.yml +3 -0
  148. data/data/codelists/codelist-9.yml +11 -0
  149. data/data/codelists/codelist-90.yml +13 -0
  150. data/data/codelists/codelist-91.yml +254 -0
  151. data/data/codelists/codelist-92.yml +11 -0
  152. data/data/codelists/codelist-93.yml +15 -0
  153. data/data/codelists/codelist-94.yml +5 -0
  154. data/data/codelists/codelist-95.yml +5 -0
  155. data/data/codelists/codelist-96.yml +193 -0
  156. data/data/codelists/codelist-97.yml +3 -0
  157. data/data/codelists/codelist-98.yml +23 -0
  158. data/data/codelists/codelist-99.yml +26 -0
  159. data/data/onix21/codelists/codelist-1.yml +14 -0
  160. data/data/onix21/codelists/codelist-10.yml +52 -0
  161. data/data/onix21/codelists/codelist-100.yml +8 -0
  162. data/data/onix21/codelists/codelist-101.yml +7 -0
  163. data/data/onix21/codelists/codelist-102.yml +5 -0
  164. data/data/onix21/codelists/codelist-11.yml +13 -0
  165. data/data/onix21/codelists/codelist-12.yml +16 -0
  166. data/data/onix21/codelists/codelist-121.yml +162 -0
  167. data/data/onix21/codelists/codelist-13.yml +11 -0
  168. data/data/onix21/codelists/codelist-138.yml +8 -0
  169. data/data/onix21/codelists/codelist-139.yml +109 -0
  170. data/data/onix21/codelists/codelist-14.yml +6 -0
  171. data/data/onix21/codelists/codelist-140.yml +9 -0
  172. data/data/onix21/codelists/codelist-141.yml +12 -0
  173. data/data/onix21/codelists/codelist-142.yml +14 -0
  174. data/data/onix21/codelists/codelist-143.yml +9 -0
  175. data/data/onix21/codelists/codelist-144.yml +8 -0
  176. data/data/onix21/codelists/codelist-145.yml +10 -0
  177. data/data/onix21/codelists/codelist-146.yml +5 -0
  178. data/data/onix21/codelists/codelist-147.yml +16 -0
  179. data/data/onix21/codelists/codelist-148.yml +6 -0
  180. data/data/onix21/codelists/codelist-149.yml +8 -0
  181. data/data/onix21/codelists/codelist-15.yml +16 -0
  182. data/data/onix21/codelists/codelist-150.yml +133 -0
  183. data/data/onix21/codelists/codelist-151.yml +10 -0
  184. data/data/onix21/codelists/codelist-152.yml +4 -0
  185. data/data/onix21/codelists/codelist-153.yml +22 -0
  186. data/data/onix21/codelists/codelist-154.yml +11 -0
  187. data/data/onix21/codelists/codelist-155.yml +10 -0
  188. data/data/onix21/codelists/codelist-156.yml +6 -0
  189. data/data/onix21/codelists/codelist-157.yml +6 -0
  190. data/data/onix21/codelists/codelist-158.yml +35 -0
  191. data/data/onix21/codelists/codelist-159.yml +8 -0
  192. data/data/onix21/codelists/codelist-16.yml +8 -0
  193. data/data/onix21/codelists/codelist-160.yml +7 -0
  194. data/data/onix21/codelists/codelist-161.yml +5 -0
  195. data/data/onix21/codelists/codelist-162.yml +9 -0
  196. data/data/onix21/codelists/codelist-163.yml +18 -0
  197. data/data/onix21/codelists/codelist-164.yml +7 -0
  198. data/data/onix21/codelists/codelist-165.yml +6 -0
  199. data/data/onix21/codelists/codelist-166.yml +6 -0
  200. data/data/onix21/codelists/codelist-167.yml +11 -0
  201. data/data/onix21/codelists/codelist-168.yml +4 -0
  202. data/data/onix21/codelists/codelist-169.yml +7 -0
  203. data/data/onix21/codelists/codelist-17.yml +98 -0
  204. data/data/onix21/codelists/codelist-170.yml +6 -0
  205. data/data/onix21/codelists/codelist-171.yml +4 -0
  206. data/data/onix21/codelists/codelist-172.yml +3 -0
  207. data/data/onix21/codelists/codelist-173.yml +5 -0
  208. data/data/onix21/codelists/codelist-174.yml +4 -0
  209. data/data/onix21/codelists/codelist-175.yml +230 -0
  210. data/data/onix21/codelists/codelist-176.yml +16 -0
  211. data/data/onix21/codelists/codelist-177.yml +4 -0
  212. data/data/onix21/codelists/codelist-178.yml +30 -0
  213. data/data/onix21/codelists/codelist-179.yml +5 -0
  214. data/data/onix21/codelists/codelist-18.yml +8 -0
  215. data/data/onix21/codelists/codelist-184.yml +10 -0
  216. data/data/onix21/codelists/codelist-19.yml +9 -0
  217. data/data/onix21/codelists/codelist-196.yml +22 -0
  218. data/data/onix21/codelists/codelist-197.yml +7 -0
  219. data/data/onix21/codelists/codelist-198.yml +8 -0
  220. data/data/onix21/codelists/codelist-2.yml +8 -0
  221. data/data/onix21/codelists/codelist-20.yml +2 -0
  222. data/data/onix21/codelists/codelist-203.yml +10 -0
  223. data/data/onix21/codelists/codelist-204.yml +7 -0
  224. data/data/onix21/codelists/codelist-21.yml +36 -0
  225. data/data/onix21/codelists/codelist-215.yml +9 -0
  226. data/data/onix21/codelists/codelist-216.yml +11 -0
  227. data/data/onix21/codelists/codelist-217.yml +3 -0
  228. data/data/onix21/codelists/codelist-218.yml +5 -0
  229. data/data/onix21/codelists/codelist-219.yml +5 -0
  230. data/data/onix21/codelists/codelist-22.yml +11 -0
  231. data/data/onix21/codelists/codelist-220.yml +7 -0
  232. data/data/onix21/codelists/codelist-23.yml +17 -0
  233. data/data/onix21/codelists/codelist-24.yml +14 -0
  234. data/data/onix21/codelists/codelist-25.yml +31 -0
  235. data/data/onix21/codelists/codelist-26.yml +100 -0
  236. data/data/onix21/codelists/codelist-27.yml +107 -0
  237. data/data/onix21/codelists/codelist-28.yml +10 -0
  238. data/data/onix21/codelists/codelist-29.yml +30 -0
  239. data/data/onix21/codelists/codelist-3.yml +13 -0
  240. data/data/onix21/codelists/codelist-30.yml +20 -0
  241. data/data/onix21/codelists/codelist-31.yml +5 -0
  242. data/data/onix21/codelists/codelist-32.yml +10 -0
  243. data/data/onix21/codelists/codelist-33.yml +46 -0
  244. data/data/onix21/codelists/codelist-34.yml +18 -0
  245. data/data/onix21/codelists/codelist-35.yml +8 -0
  246. data/data/onix21/codelists/codelist-36.yml +5 -0
  247. data/data/onix21/codelists/codelist-37.yml +8 -0
  248. data/data/onix21/codelists/codelist-38.yml +42 -0
  249. data/data/onix21/codelists/codelist-39.yml +21 -0
  250. data/data/onix21/codelists/codelist-40.yml +8 -0
  251. data/data/onix21/codelists/codelist-41.yml +9 -0
  252. data/data/onix21/codelists/codelist-42.yml +18 -0
  253. data/data/onix21/codelists/codelist-43.yml +9 -0
  254. data/data/onix21/codelists/codelist-44.yml +27 -0
  255. data/data/onix21/codelists/codelist-45.yml +20 -0
  256. data/data/onix21/codelists/codelist-46.yml +11 -0
  257. data/data/onix21/codelists/codelist-47.yml +6 -0
  258. data/data/onix21/codelists/codelist-48.yml +13 -0
  259. data/data/onix21/codelists/codelist-49.yml +281 -0
  260. data/data/onix21/codelists/codelist-5.yml +20 -0
  261. data/data/onix21/codelists/codelist-50.yml +10 -0
  262. data/data/onix21/codelists/codelist-51.yml +37 -0
  263. data/data/onix21/codelists/codelist-52.yml +3 -0
  264. data/data/onix21/codelists/codelist-53.yml +7 -0
  265. data/data/onix21/codelists/codelist-54.yml +25 -0
  266. data/data/onix21/codelists/codelist-55.yml +21 -0
  267. data/data/onix21/codelists/codelist-56.yml +4 -0
  268. data/data/onix21/codelists/codelist-57.yml +7 -0
  269. data/data/onix21/codelists/codelist-58.yml +27 -0
  270. data/data/onix21/codelists/codelist-59.yml +12 -0
  271. data/data/onix21/codelists/codelist-6.yml +78 -0
  272. data/data/onix21/codelists/codelist-60.yml +4 -0
  273. data/data/onix21/codelists/codelist-61.yml +5 -0
  274. data/data/onix21/codelists/codelist-62.yml +7 -0
  275. data/data/onix21/codelists/codelist-63.yml +2 -0
  276. data/data/onix21/codelists/codelist-64.yml +18 -0
  277. data/data/onix21/codelists/codelist-65.yml +31 -0
  278. data/data/onix21/codelists/codelist-66.yml +6 -0
  279. data/data/onix21/codelists/codelist-67.yml +4 -0
  280. data/data/onix21/codelists/codelist-68.yml +19 -0
  281. data/data/onix21/codelists/codelist-69.yml +6 -0
  282. data/data/onix21/codelists/codelist-7.yml +132 -0
  283. data/data/onix21/codelists/codelist-70.yml +4 -0
  284. data/data/onix21/codelists/codelist-71.yml +14 -0
  285. data/data/onix21/codelists/codelist-72.yml +9 -0
  286. data/data/onix21/codelists/codelist-73.yml +43 -0
  287. data/data/onix21/codelists/codelist-74.yml +492 -0
  288. data/data/onix21/codelists/codelist-75.yml +4 -0
  289. data/data/onix21/codelists/codelist-76.yml +14 -0
  290. data/data/onix21/codelists/codelist-77.yml +21 -0
  291. data/data/onix21/codelists/codelist-78.yml +191 -0
  292. data/data/onix21/codelists/codelist-79.yml +26 -0
  293. data/data/onix21/codelists/codelist-8.yml +9 -0
  294. data/data/onix21/codelists/codelist-80.yml +23 -0
  295. data/data/onix21/codelists/codelist-81.yml +41 -0
  296. data/data/onix21/codelists/codelist-82.yml +19 -0
  297. data/data/onix21/codelists/codelist-83.yml +72 -0
  298. data/data/onix21/codelists/codelist-84.yml +12 -0
  299. data/data/onix21/codelists/codelist-85.yml +25 -0
  300. data/data/onix21/codelists/codelist-86.yml +7 -0
  301. data/data/onix21/codelists/codelist-87.yml +8 -0
  302. data/data/onix21/codelists/codelist-88.yml +2 -0
  303. data/data/onix21/codelists/codelist-89.yml +3 -0
  304. data/data/onix21/codelists/codelist-9.yml +13 -0
  305. data/data/onix21/codelists/codelist-90.yml +13 -0
  306. data/data/onix21/codelists/codelist-91.yml +254 -0
  307. data/data/onix21/codelists/codelist-92.yml +11 -0
  308. data/data/onix21/codelists/codelist-93.yml +15 -0
  309. data/data/onix21/codelists/codelist-94.yml +5 -0
  310. data/data/onix21/codelists/codelist-95.yml +5 -0
  311. data/data/onix21/codelists/codelist-96.yml +194 -0
  312. data/data/onix21/codelists/codelist-97.yml +3 -0
  313. data/data/onix21/codelists/codelist-98.yml +25 -0
  314. data/data/onix21/codelists/codelist-99.yml +26 -0
  315. data/data/onix21/shortnames.yml +431 -0
  316. data/data/shortnames.yml +395 -0
  317. data/lib/im_onix.rb +2 -0
  318. data/lib/onix/code.rb +543 -0
  319. data/lib/onix/collateral_detail.rb +94 -0
  320. data/lib/onix/contributor.rb +87 -0
  321. data/lib/onix/date.rb +183 -0
  322. data/lib/onix/descriptive_detail.rb +552 -0
  323. data/lib/onix/discount_coded.rb +20 -0
  324. data/lib/onix/entity.rb +135 -0
  325. data/lib/onix/error.rb +6 -0
  326. data/lib/onix/helper.rb +66 -0
  327. data/lib/onix/identifier.rb +158 -0
  328. data/lib/onix/onix21.rb +604 -0
  329. data/lib/onix/onix_message.rb +187 -0
  330. data/lib/onix/price.rb +74 -0
  331. data/lib/onix/product.rb +846 -0
  332. data/lib/onix/product_supply.rb +89 -0
  333. data/lib/onix/publishing_detail.rb +86 -0
  334. data/lib/onix/related_material.rb +30 -0
  335. data/lib/onix/related_product.rb +45 -0
  336. data/lib/onix/related_work.rb +24 -0
  337. data/lib/onix/sales_outlet.rb +14 -0
  338. data/lib/onix/sales_restriction.rb +37 -0
  339. data/lib/onix/sales_rights.rb +12 -0
  340. data/lib/onix/subject.rb +35 -0
  341. data/lib/onix/subset.rb +334 -0
  342. data/lib/onix/supporting_resource.rb +192 -0
  343. data/lib/onix/tax.rb +23 -0
  344. data/lib/onix/territory.rb +56 -0
  345. data/lib/onix/website.rb +21 -0
  346. metadata +477 -0
@@ -0,0 +1,846 @@
1
+ require 'onix/helper'
2
+ require 'onix/code'
3
+ require 'onix/entity'
4
+ require 'onix/descriptive_detail'
5
+ require 'onix/publishing_detail'
6
+ require 'onix/collateral_detail'
7
+ require 'onix/related_material'
8
+ require 'onix/supporting_resource'
9
+ require 'onix/subject'
10
+ require 'onix/contributor'
11
+ require 'onix/product_supply'
12
+ require 'onix/territory'
13
+ require 'onix/error'
14
+
15
+ module ONIX
16
+ # flattened supplies extractor
17
+ module ProductSuppliesExtractor
18
+ # class must define a product_supplies returning an Array of objects responding to :
19
+ # - availability_date (Date)
20
+ # - countries (country code Array)
21
+
22
+ # :category: High level
23
+ # flattened supplies with prices
24
+ #
25
+ # supplies is a hash symbol array in the form :
26
+ # [{:available=>bool,
27
+ # :availability_date=>date,
28
+ # :including_tax=>bool,
29
+ # :currency=>string,
30
+ # :territory=>string,
31
+ # :suppliers=>[Supplier,...],
32
+ # :prices=>[{:amount=>int,
33
+ # :from_date=>date,
34
+ # :until_date=>date,
35
+ # :tax=>{:amount=>int, :rate_percent=>float}}]}]
36
+ def supplies(keep_all_prices_dates=false)
37
+ supplies=[]
38
+
39
+ # add territories if missing
40
+ if self.product_supplies
41
+ self.product_supplies.each do |ps|
42
+ ps.supply_details.each do |sd|
43
+ sd.prices.each do |p|
44
+ supply={}
45
+ supply[:suppliers]=sd.suppliers
46
+ supply[:available]=sd.available?
47
+ supply[:availability_date]=sd.availability_date
48
+
49
+ unless supply[:availability_date]
50
+ if ps.availability_date
51
+ supply[:availability_date]=ps.market_publishing_detail.availability_date
52
+ end
53
+ end
54
+ supply[:price]=p.amount
55
+ supply[:qualifier]=p.qualifier.human if p.qualifier
56
+ supply[:including_tax]=p.including_tax?
57
+ if !p.territory or p.territory.countries.length==0
58
+ supply[:territory]=[]
59
+ supply[:territory]=ps.countries
60
+
61
+ if supply[:territory].length==0
62
+ if @publishing_detail
63
+ supply[:territory]=self.countries_rights
64
+ end
65
+ end
66
+ else
67
+ supply[:territory]=p.territory.countries
68
+ end
69
+ supply[:from_date]=p.from_date
70
+ supply[:until_date]=p.until_date
71
+ supply[:currency]=p.currency
72
+ supply[:tax]=p.tax
73
+
74
+ unless supply[:availability_date]
75
+ if @publishing_detail
76
+ supply[:availability_date]=@publishing_detail.publication_date
77
+ end
78
+ end
79
+
80
+ supplies << supply
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ grouped_supplies={}
87
+ supplies.each do |supply|
88
+ pr_key="#{supply[:available]}_#{supply[:including_tax]}_#{supply[:currency]}_#{supply[:territory].join('_')}"
89
+ grouped_supplies[pr_key]||=[]
90
+ grouped_supplies[pr_key] << supply
91
+ end
92
+
93
+ nb_suppliers = supplies.map{|s| s[:suppliers][0].name}.uniq.length
94
+ # render prices sequentially with dates
95
+ grouped_supplies.each do |ksup, supply|
96
+ if supply.length > 1
97
+ global_price=supply.select{|p| not p[:from_date] and not p[:until_date]}
98
+ global_price=global_price.first
99
+
100
+ if global_price
101
+ if nb_suppliers > 1
102
+ grouped_supplies[ksup] += self.prices_with_periods(supply, global_price)
103
+ else
104
+ grouped_supplies[ksup] = self.prices_with_periods(supply, global_price)
105
+ end
106
+ grouped_supplies[ksup].uniq!
107
+ else
108
+ # remove explicit from date
109
+ explicit_from=supply.select{|p| p[:from_date] and not supply.select{|sp| sp[:until_date] and sp[:until_date]<=p[:from_date]}.first}.first
110
+ if explicit_from
111
+ explicit_from[:from_date]=nil unless keep_all_prices_dates
112
+ end
113
+ end
114
+
115
+
116
+ else
117
+ supply.each do |s|
118
+ if s[:from_date] and s[:availability_date] and s[:from_date] >= s[:availability_date]
119
+ s[:availability_date]=s[:from_date]
120
+ end
121
+ s[:from_date]=nil unless keep_all_prices_dates
122
+
123
+ end
124
+ end
125
+ end
126
+
127
+ # merge by territories
128
+ grouped_territories_supplies={}
129
+ grouped_supplies.each do |ksup,supply|
130
+ fsupply=supply.first
131
+ pr_key="#{fsupply[:available]}_#{fsupply[:including_tax]}_#{fsupply[:currency]}"
132
+ supply.each do |s|
133
+ pr_key+="_#{s[:price]}_#{s[:from_date]}_#{s[:until_date]}"
134
+ end
135
+ grouped_territories_supplies[pr_key]||=[]
136
+ grouped_territories_supplies[pr_key] << supply
137
+ end
138
+
139
+ supplies=[]
140
+
141
+ grouped_territories_supplies.each do |ksup,supply|
142
+ fsupply=supply.first.first
143
+ supplies << {:including_tax=>fsupply[:including_tax],:currency=>fsupply[:currency],
144
+ :territory=>supply.map{|fs| fs.map{|s| s[:territory]}}.flatten.uniq,
145
+ :available=>fsupply[:available],
146
+ :availability_date=>fsupply[:availability_date],
147
+ :suppliers=>fsupply[:suppliers],
148
+ :prices=>supply.first.map{|s|
149
+
150
+ s[:amount]=s[:price]
151
+ s.delete(:price)
152
+ s.delete(:available)
153
+ s.delete(:currency)
154
+ s.delete(:availability_date)
155
+ s.delete(:including_tax)
156
+ s.delete(:territory)
157
+ s
158
+ }}
159
+ end
160
+
161
+ supplies
162
+ end
163
+
164
+ # add missing periods when they can be guessed
165
+ def prices_with_periods(supplies, global_supply)
166
+ complete_supplies = supplies.select{ |supply| supply[:from_date] && supply[:until_date] }.sort_by { |supply| supply[:from_date] }
167
+ missing_start_period_supplies = supplies.select{ |supply| supply[:from_date] && !supply[:until_date] }.sort_by { |supply| supply[:from_date] }
168
+ missing_end_period_supplies = supplies.select{ |supply| !supply[:from_date] && supply[:until_date] }.sort_by { |supply| supply[:until_date] }
169
+
170
+ return [global_supply] if [complete_supplies, missing_start_period_supplies, missing_end_period_supplies].all? {|supply| supply.empty? }
171
+
172
+ return self.add_missing_periods(complete_supplies, global_supply) unless complete_supplies.empty?
173
+
174
+ without_start = missing_start_period_supplies.length == 1 && complete_supplies.empty? && missing_end_period_supplies.empty?
175
+ without_end = missing_end_period_supplies.length == 1 && complete_supplies.empty? && missing_start_period_supplies.empty?
176
+
177
+ return self.add_starting_period(missing_start_period_supplies.first, global_supply) if without_start
178
+ return self.add_ending_period(missing_end_period_supplies.first, global_supply) if without_end
179
+
180
+ [global_supply]
181
+ end
182
+
183
+ def add_missing_periods(supplies, global_supply)
184
+ new_supplies = []
185
+
186
+ supplies.each.with_index do |supply, index|
187
+ new_supplies << global_supply.dup.tap{ |start_sup| start_sup[:until_date] = supply[:from_date] - 1 } if index == 0
188
+
189
+ if index > 0 && index != supplies.length
190
+ new_supplies << global_supply.dup.tap do |missing_supply|
191
+ missing_supply[:from_date] = supplies[index - 1][:until_date] + 1
192
+ missing_supply[:until_date] = supply[:from_date] - 1
193
+ end
194
+ end
195
+
196
+ new_supplies << supply
197
+
198
+ new_supplies << global_supply.dup.tap{ |end_sup| end_sup[:from_date] = supply[:until_date] + 1 } if index == supplies.length - 1
199
+ end
200
+
201
+ new_supplies
202
+ end
203
+
204
+ def add_starting_period(supply, global_supply)
205
+ missing_supply = global_supply.dup
206
+ missing_supply[:until_date] = supply[:from_date] - 1
207
+
208
+ [missing_supply, supply]
209
+ end
210
+
211
+ def add_ending_period(supply, global_supply)
212
+ missing_supply = global_supply.dup
213
+ missing_supply[:from_date] = supply[:until_date] + 1
214
+
215
+ [supply, missing_supply]
216
+ end
217
+
218
+ # :category: High level
219
+ # flattened supplies only including taxes
220
+ def supplies_including_tax
221
+ self.supplies.select{|p| p[:including_tax]}
222
+ end
223
+
224
+ # :category: High level
225
+ # flattened supplies only excluding taxes
226
+ def supplies_excluding_tax
227
+ self.supplies.select{|p| not p[:including_tax]}
228
+ end
229
+
230
+ # :category: High level
231
+ # flattened supplies with default tax (excluding tax for US and CA, including otherwise)
232
+ def supplies_with_default_tax
233
+ self.supplies_including_tax + self.supplies_excluding_tax.select{|s| ["CAD","USD"].include?(s[:currency])}
234
+ end
235
+
236
+ # :category: High level
237
+ # flattened supplies for country
238
+ def supplies_for_country(country,currency=nil)
239
+ country_supplies=self.supplies
240
+ if currency
241
+ country_supplies=country_supplies.select{|s| s[:currency]==currency}
242
+ end
243
+ country_supplies.select{|s|
244
+ if s[:territory].include?(country)
245
+ true
246
+ else
247
+ false
248
+ end
249
+ }
250
+ end
251
+
252
+ # :category: High level
253
+ # price amount for given +currency+ and country at time
254
+ def at_time_price_amount_for(time,currency,country=nil)
255
+ sups=self.supplies_with_default_tax.select { |p| p[:currency]==currency }
256
+ if country
257
+ sups=sups.select{|p| p[:territory].include?(country)}
258
+ end
259
+ if sups.length > 0
260
+ # exclusive
261
+ sup=sups.first[:prices].select { |p|
262
+ (!p[:from_date] or p[:from_date].to_date <= time.to_date) and
263
+ (!p[:until_date] or p[:until_date].to_date > time.to_date)
264
+ }.first
265
+
266
+ if sup
267
+ sup[:amount]
268
+ else
269
+ # or inclusive
270
+ sup=sups.first[:prices].select { |p|
271
+ (!p[:from_date] or p[:from_date].to_date <= time.to_date) and
272
+ (!p[:until_date] or p[:until_date].to_date >= time.to_date)
273
+ }.first
274
+
275
+ if sup
276
+ sup[:amount]
277
+ else
278
+ nil
279
+ end
280
+ end
281
+
282
+ else
283
+ nil
284
+ end
285
+ end
286
+
287
+ # :category: High level
288
+ # current price amount for given +currency+ and country
289
+ def current_price_amount_for(currency,country=nil)
290
+ at_time_price_amount_for(Time.now,currency,country)
291
+ end
292
+ end
293
+
294
+ class Product < SubsetDSL
295
+ include EanMethods
296
+ include IsbnMethods
297
+ include ProprietaryIdMethods
298
+
299
+ element "RecordReference", :text
300
+ element "NotificationType", :subset
301
+ element "RecordSourceName", :text
302
+ elements "ProductIdentifier", :subset
303
+ element "DescriptiveDetail", :subset
304
+ element "CollateralDetail", :subset
305
+ element "PublishingDetail", :subset
306
+ element "RelatedMaterial", :subset
307
+ elements "ProductSupply", :subset
308
+
309
+ # shortcuts
310
+ def identifiers
311
+ @product_identifiers
312
+ end
313
+
314
+ # default LanguageCode from ONIXMessage
315
+ attr_accessor :default_language_of_text
316
+ # default code from ONIXMessage
317
+ attr_accessor :default_currency_code
318
+
319
+ include ProductSuppliesExtractor
320
+
321
+ # :category: High level
322
+ # product title string
323
+ def title
324
+ @descriptive_detail.title
325
+ end
326
+
327
+ # :category: High level
328
+ # product subtitle string
329
+ def subtitle
330
+ @descriptive_detail.subtitle
331
+ end
332
+
333
+ # :category: High level
334
+ # product description string including HTML
335
+ def description
336
+ if @collateral_detail
337
+ @collateral_detail.description
338
+ else
339
+ nil
340
+ end
341
+ end
342
+
343
+ # :category: High level
344
+ # product larger front cover URL string
345
+ def frontcover_url
346
+ if @collateral_detail
347
+ @collateral_detail.frontcover_url
348
+ end
349
+ end
350
+
351
+ # :category: High level
352
+ # product larger front cover last updated date
353
+ def frontcover_last_updated
354
+ if @collateral_detail
355
+ @collateral_detail.frontcover_last_updated
356
+ end
357
+ end
358
+
359
+ # :category: High level
360
+ # product larger front cover mimetype
361
+ def frontcover_mimetype
362
+ if @collateral_detail
363
+ @collateral_detail.frontcover_mimetype
364
+ end
365
+ end
366
+
367
+ # :category: High level
368
+ # ePub sample URL string
369
+ def epub_sample_url
370
+ if @collateral_detail
371
+ @collateral_detail.epub_sample_url
372
+ end
373
+ end
374
+
375
+ # :category: High level
376
+ # ePub sample last updated date
377
+ def epub_sample_last_updated
378
+ if @collateral_detail
379
+ @collateral_detail.epub_sample_last_updated
380
+ end
381
+ end
382
+
383
+ # :category: High level
384
+ # ePub sample mimetype
385
+ def epub_sample_mimetype
386
+ if @collateral_detail
387
+ @collateral_detail.epub_sample_mimetype
388
+ end
389
+ end
390
+
391
+ # :category: High level
392
+ # product edition number
393
+ def edition_number
394
+ @descriptive_detail.edition_number
395
+ end
396
+
397
+ # product LanguageCode of text
398
+ def language_of_text
399
+ @descriptive_detail.language_of_text || @default_language_of_text
400
+ end
401
+
402
+ # :category: High level
403
+ # product language code string of text (eg: fre)
404
+ def language_code_of_text
405
+ if self.language_of_text
406
+ self.language_of_text.code
407
+ end
408
+ end
409
+
410
+ # :category: High level
411
+ # product language name string of text (eg: French)
412
+ def language_name_of_text
413
+ if self.language_of_text
414
+ self.language_of_text.human
415
+ end
416
+ end
417
+
418
+ # :category: High level
419
+ # publisher collection title
420
+ def publisher_collection_title
421
+ @descriptive_detail.publisher_collection_title
422
+ end
423
+
424
+ def subjects
425
+ @descriptive_detail.subjects
426
+ end
427
+
428
+ # BISAC categories Subject
429
+ def bisac_categories
430
+ @descriptive_detail.bisac_categories
431
+ end
432
+
433
+ # :category: High level
434
+ # BISAC categories identifiers string array (eg: FIC000000)
435
+ def bisac_categories_codes
436
+ self.bisac_categories.map{|c| c.code}.uniq
437
+ end
438
+
439
+ # CLIL categories Subject
440
+ def clil_categories
441
+ @descriptive_detail.clil_categories
442
+ end
443
+
444
+ # :category: High level
445
+ # CLIL categories identifier string array
446
+ def clil_categories_codes
447
+ self.clil_categories.map{|c| c.code}.uniq
448
+ end
449
+
450
+ # :category: High level
451
+ # keywords string array
452
+ def keywords
453
+ @descriptive_detail.keywords
454
+ end
455
+
456
+ # :category: High level
457
+ # Protection type string (None, Watermarking, Drm, AdobeDrm)
458
+ def protection_type
459
+ @descriptive_detail.protection_type
460
+ end
461
+
462
+ # :category: High level
463
+ # List of protections type string (None, Watermarking, DRM, AdobeDRM)
464
+ def protections
465
+ @descriptive_detail.protections
466
+ end
467
+
468
+ # :category: High level
469
+ # product has DRM ?
470
+ def drmized?
471
+ if @protections.any? {|p| p =~ /Drm/ }
472
+ true
473
+ else
474
+ false
475
+ end
476
+ end
477
+
478
+ # :category: High level
479
+ # is product digital ?
480
+ def digital?
481
+ @descriptive_detail.digital?
482
+ end
483
+
484
+ # :category: High level
485
+ # is product audio ?
486
+ def audio?
487
+ @descriptive_detail.audio?
488
+ end
489
+
490
+ # :category: High level
491
+ # is product digital ?
492
+ def streaming?
493
+ @descriptive_detail.streaming?
494
+ end
495
+
496
+ # :category: High level
497
+ # is product a bundle of multiple parts ?
498
+ def bundle?
499
+ @descriptive_detail.bundle?
500
+ end
501
+
502
+ def sold_separately?
503
+ @product_supplies.map{|ps| ps.supply_details.map{|sd| sd.sold_separately?}.flatten}.flatten.uniq.first
504
+ end
505
+
506
+ # :category: High level
507
+ # bundle ProductPart array
508
+ def parts
509
+ @descriptive_detail.parts
510
+ end
511
+
512
+ # :category: High level
513
+ # digital file filesize in bytes
514
+ def filesize
515
+ @descriptive_detail.filesize
516
+ end
517
+
518
+ # :category: High level
519
+ # audio formats array
520
+ def audio_formats
521
+ @descriptive_detail.audio_formats
522
+ end
523
+
524
+ # :category: High level
525
+ # audio format string ()
526
+ def audio_format
527
+ @descriptive_detail.audio_format
528
+ end
529
+
530
+ # :category: High level
531
+ # digital file format string (Epub,Pdf,Mobipocket)
532
+ def file_format
533
+ @descriptive_detail.file_format
534
+ end
535
+
536
+ def form_details
537
+ @descriptive_detail.form_details
538
+ end
539
+
540
+ def reflowable?
541
+ @descriptive_detail.reflowable?
542
+ end
543
+
544
+ # :category: High level
545
+ # digital file mimetype (Epub,Pdf,Mobipocket)
546
+ def file_mimetype
547
+ @descriptive_detail.file_mimetype
548
+ end
549
+
550
+ # :category: High level
551
+ # digital file description string
552
+ def file_description
553
+ @descriptive_detail.file_description
554
+ end
555
+
556
+ # :category: High level
557
+ # raw file description string without HTML
558
+ def raw_file_description
559
+ if @descriptive_detail.file_description
560
+ Helper.strip_html(@descriptive_detail.file_description).gsub(/\s+/," ").strip
561
+ else
562
+ nil
563
+ end
564
+ end
565
+
566
+ # :category: High level
567
+ # page count
568
+ def pages
569
+ @descriptive_detail.pages
570
+ end
571
+
572
+ # :category: High level
573
+ # raw book description string without HTML
574
+ def raw_description
575
+ if self.description
576
+ Helper.strip_html(self.description).gsub(/\s+/," ").strip
577
+ else
578
+ nil
579
+ end
580
+ end
581
+
582
+ def publishers
583
+ if @publishing_detail
584
+ @publishing_detail.publishers
585
+ else
586
+ []
587
+ end
588
+ end
589
+
590
+ def publisher
591
+ if @publishing_detail
592
+ @publishing_detail.publisher
593
+ else
594
+ nil
595
+ end
596
+ end
597
+
598
+ # :category: High level
599
+ # publisher name string, if multiple publishers are found, then they are concatenated with " / "
600
+ def publisher_name
601
+ if self.publishers.length > 0
602
+ self.publishers.map{|p| p.name}.join(" / ")
603
+ end
604
+ end
605
+
606
+ # :category: High level
607
+ # publisher GLN string, nil if multiple publishers are found
608
+ def publisher_gln
609
+ if self.publishers.length==1
610
+ self.publisher.gln
611
+ end
612
+ end
613
+
614
+ def imprint
615
+ if @publishing_detail
616
+ @publishing_detail.imprint
617
+ else
618
+ nil
619
+ end
620
+ end
621
+
622
+ # :category: High level
623
+ # imprint name string
624
+ def imprint_name
625
+ if self.imprint
626
+ self.imprint.name
627
+ else
628
+ nil
629
+ end
630
+ end
631
+
632
+ # :category: High level
633
+ # imprint GLN string
634
+ def imprint_gln
635
+ if self.imprint
636
+ self.imprint.gln
637
+ end
638
+ end
639
+
640
+ def distributors
641
+ @product_supplies.map{|ps| ps.distributors}.flatten.uniq{|d| d.name}
642
+ end
643
+
644
+ # product distributor
645
+ def distributor
646
+ if self.distributors.length > 0
647
+ if self.distributors.length==1
648
+ self.distributors.first
649
+ else
650
+ raise ExpectsOneButHasSeveral, self.distributors.map(&:name)
651
+ end
652
+ else
653
+ nil
654
+ end
655
+ end
656
+
657
+ # :category: High level
658
+ # product distributor name string
659
+ def distributor_name
660
+ if self.distributor
661
+ self.distributor.name
662
+ else
663
+ nil
664
+ end
665
+ end
666
+
667
+ # :category: High level
668
+ # product distributor GLN string
669
+ def distributor_gln
670
+ if self.distributor
671
+ self.distributor.gln
672
+ else
673
+ nil
674
+ end
675
+ end
676
+
677
+ # :category: High level
678
+ # return every related subset
679
+ def related
680
+ if @related_material
681
+ (@related_material.related_products + @related_material.related_works)
682
+ else
683
+ []
684
+ end
685
+ end
686
+
687
+ # :category: High level
688
+ # paper linking RelatedProduct
689
+ def part_of_product
690
+ if @related_material
691
+ @related_material.part_of_products.first
692
+ end
693
+ end
694
+
695
+ # :category: High level
696
+ # paper linking RelatedProduct
697
+ def print_product
698
+ if @related_material
699
+ @related_material.print_products.first
700
+ end
701
+ end
702
+
703
+ # DEPRECATED see print_product instead
704
+ def paper_linking
705
+ self.print_product
706
+ end
707
+
708
+ # :category: High level
709
+ # date of publication
710
+ def publication_date
711
+ if @publishing_detail
712
+ @publishing_detail.publication_date
713
+ end
714
+ end
715
+
716
+ # date of embargo
717
+ def embargo_date
718
+ if @publishing_detail
719
+ @publishing_detail.embargo_date
720
+ end
721
+ end
722
+
723
+ def preorder_embargo_date
724
+ if @publishing_detail
725
+ @publishing_detail.preorder_embargo_date
726
+ end
727
+ end
728
+
729
+ def public_announcement_date
730
+ if @publishing_detail
731
+ @publishing_detail.public_announcement_date
732
+ end
733
+ end
734
+
735
+ def sales_restriction
736
+ if @publishing_detail
737
+ @publishing_detail.sales_restriction
738
+ end
739
+ end
740
+
741
+ # :category: High level
742
+ # product countries rights string array
743
+ def countries_rights
744
+ countries=[]
745
+ if @publishing_detail
746
+ countries+=@publishing_detail.sales_rights.map{|sr| sr.territory.countries}.flatten.uniq
747
+ end
748
+
749
+ if @product_supplies
750
+ countries+=@product_supplies.map{|ps| ps.markets.map{|m| m.territory.countries}.flatten}.flatten.uniq
751
+ end
752
+
753
+ countries.uniq
754
+ end
755
+
756
+ # :category: High level
757
+ def illustrations
758
+ return [] unless @collateral_detail && @collateral_detail.supporting_resources
759
+
760
+ @collateral_detail.supporting_resources.image.map do |image_resource|
761
+ {
762
+ :url => image_resource.versions.last.links.first.strip,
763
+ :type => image_resource.type.human,
764
+ :width => image_resource.versions.last.image_width,
765
+ :height => image_resource.versions.last.image_height,
766
+ :caption => image_resource.caption,
767
+ :format_code => image_resource.versions.last.file_format,
768
+ :updated_at => image_resource.versions.last.last_updated_utc
769
+ }
770
+ end
771
+ end
772
+
773
+ # :category: High level
774
+ def excerpts
775
+ return [] unless @collateral_detail && @collateral_detail.supporting_resources
776
+
777
+ @collateral_detail.supporting_resources.sample_content.human_code_match(:resource_mode,["Text","Multimode"]).map do |resource|
778
+ {
779
+ :url => resource.versions.last.links.first.strip,
780
+ :form => resource.versions.last.form.human,
781
+ :md5 => resource.versions.last.md5_hash,
782
+ :format_code => resource.versions.last.file_format,
783
+ :updated_at => resource.versions.last.last_updated_utc
784
+ }
785
+ end
786
+ end
787
+
788
+ def available_product_supplies
789
+ @product_supplies.select{|ps| ps.available?}
790
+ end
791
+
792
+ # :category: High level
793
+ # is product available ?
794
+ def available?
795
+ self.available_product_supplies.length > 0 and not self.delete?
796
+ end
797
+
798
+ # :category: High level
799
+ # is product available for given +country+ ?
800
+ def available_for_country?(country)
801
+ self.supplies_for_country(country).select{|s| s[:available]}.length > 0 and self.available?
802
+ end
803
+
804
+ # :category: High level
805
+ # is product price to be announced ?
806
+ def price_to_be_announced?
807
+ unless self.product_supplies.empty? || self.product_supplies.first.supply_details.empty?
808
+ unpriced_item_type = self.product_supplies.first.supply_details.first.unpriced_item_type
809
+ end
810
+ unpriced_item_type ? unpriced_item_type.human=="PriceToBeAnnounced" : false
811
+ end
812
+
813
+ # :category: High level
814
+ # is a deletion notification ?
815
+ def delete?
816
+ self.notification_type.human=="Delete"
817
+ end
818
+
819
+ # :category: High level
820
+ # Contributor array
821
+ def contributors
822
+ @descriptive_detail.contributors
823
+ end
824
+
825
+ # :category: High level
826
+ # List of ONIX outlets values
827
+ def onix_outlets_values
828
+ if @publishing_detail
829
+ @publishing_detail.sales_rights.map { |sri|
830
+ sri.sales_restrictions.select { |sr| (!sr.start_date or sr.start_date <= Date.today) and (!sr.end_date or sr.end_date >= Date.today) }.map { |sr|
831
+ sr.sales_outlets.select { |so|
832
+ so.identifier and so.identifier.type.human=="OnixSalesOutletIdCode" }.map { |so| so.identifier.value } } }.flatten
833
+ else
834
+ []
835
+ end
836
+ end
837
+
838
+ def parse(n)
839
+ super
840
+ parts.each do |part|
841
+ part.part_of=self
842
+ end
843
+ end
844
+
845
+ end
846
+ end