im_onix 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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