@k2works/claude-code-booster 6.2.0 → 6.3.1

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 (618) hide show
  1. package/lib/assets/.claude/skills/practicing-getting-start-tdd/SKILL.md +3 -7
  2. package/lib/assets/docs/article/index.md +17 -41
  3. package/lib/assets/docs/index.md +1 -1
  4. package/lib/assets/mkdocs.yml +0 -6
  5. package/package.json +1 -1
  6. package/lib/assets/docs/article/functional-desgin-ppp/all/01-immutability-and-data-transformation.md +0 -484
  7. package/lib/assets/docs/article/functional-desgin-ppp/all/02-function-composition.md +0 -528
  8. package/lib/assets/docs/article/functional-desgin-ppp/all/03-polymorphism.md +0 -546
  9. package/lib/assets/docs/article/functional-desgin-ppp/all/04-data-validation.md +0 -309
  10. package/lib/assets/docs/article/functional-desgin-ppp/all/05-property-based-testing.md +0 -329
  11. package/lib/assets/docs/article/functional-desgin-ppp/all/06-tdd-and-functional.md +0 -507
  12. package/lib/assets/docs/article/functional-desgin-ppp/all/07-composite-pattern.md +0 -307
  13. package/lib/assets/docs/article/functional-desgin-ppp/all/08-decorator-pattern.md +0 -300
  14. package/lib/assets/docs/article/functional-desgin-ppp/all/09-adapter-pattern.md +0 -345
  15. package/lib/assets/docs/article/functional-desgin-ppp/all/10-strategy-pattern.md +0 -312
  16. package/lib/assets/docs/article/functional-desgin-ppp/all/11-command-pattern.md +0 -295
  17. package/lib/assets/docs/article/functional-desgin-ppp/all/12-visitor-pattern.md +0 -331
  18. package/lib/assets/docs/article/functional-desgin-ppp/all/13-abstract-factory-pattern.md +0 -328
  19. package/lib/assets/docs/article/functional-desgin-ppp/all/14-abstract-server-pattern.md +0 -374
  20. package/lib/assets/docs/article/functional-desgin-ppp/all/15-gossiping-bus-drivers.md +0 -165
  21. package/lib/assets/docs/article/functional-desgin-ppp/all/16-payroll-system.md +0 -187
  22. package/lib/assets/docs/article/functional-desgin-ppp/all/17-video-rental-system.md +0 -321
  23. package/lib/assets/docs/article/functional-desgin-ppp/all/18-concurrency-system.md +0 -296
  24. package/lib/assets/docs/article/functional-desgin-ppp/all/19-wa-tor-simulation.md +0 -295
  25. package/lib/assets/docs/article/functional-desgin-ppp/all/20-pattern-interactions.md +0 -283
  26. package/lib/assets/docs/article/functional-desgin-ppp/all/21-best-practices.md +0 -303
  27. package/lib/assets/docs/article/functional-desgin-ppp/all/22-oo-to-fp-migration.md +0 -346
  28. package/lib/assets/docs/article/functional-desgin-ppp/all/index.md +0 -388
  29. package/lib/assets/docs/article/functional-desgin-ppp/clojure/01-immutability-and-data-transformation.md +0 -282
  30. package/lib/assets/docs/article/functional-desgin-ppp/clojure/02-function-composition.md +0 -389
  31. package/lib/assets/docs/article/functional-desgin-ppp/clojure/03-polymorphism.md +0 -393
  32. package/lib/assets/docs/article/functional-desgin-ppp/clojure/04-clojure-spec.md +0 -359
  33. package/lib/assets/docs/article/functional-desgin-ppp/clojure/05-property-based-testing.md +0 -361
  34. package/lib/assets/docs/article/functional-desgin-ppp/clojure/06-tdd-in-functional.md +0 -392
  35. package/lib/assets/docs/article/functional-desgin-ppp/clojure/07-composite-pattern.md +0 -538
  36. package/lib/assets/docs/article/functional-desgin-ppp/clojure/08-decorator-pattern.md +0 -404
  37. package/lib/assets/docs/article/functional-desgin-ppp/clojure/09-adapter-pattern.md +0 -408
  38. package/lib/assets/docs/article/functional-desgin-ppp/clojure/10-strategy-pattern.md +0 -494
  39. package/lib/assets/docs/article/functional-desgin-ppp/clojure/11-command-pattern.md +0 -575
  40. package/lib/assets/docs/article/functional-desgin-ppp/clojure/12-visitor-pattern.md +0 -576
  41. package/lib/assets/docs/article/functional-desgin-ppp/clojure/13-abstract-factory-pattern.md +0 -484
  42. package/lib/assets/docs/article/functional-desgin-ppp/clojure/14-abstract-server-pattern.md +0 -471
  43. package/lib/assets/docs/article/functional-desgin-ppp/clojure/15-gossiping-bus-drivers.md +0 -334
  44. package/lib/assets/docs/article/functional-desgin-ppp/clojure/16-payroll-system.md +0 -410
  45. package/lib/assets/docs/article/functional-desgin-ppp/clojure/17-video-rental-system.md +0 -459
  46. package/lib/assets/docs/article/functional-desgin-ppp/clojure/18-concurrency-system.md +0 -484
  47. package/lib/assets/docs/article/functional-desgin-ppp/clojure/19-wator-simulation.md +0 -748
  48. package/lib/assets/docs/article/functional-desgin-ppp/clojure/20-pattern-interactions.md +0 -576
  49. package/lib/assets/docs/article/functional-desgin-ppp/clojure/21-best-practices.md +0 -527
  50. package/lib/assets/docs/article/functional-desgin-ppp/clojure/22-oo-to-fp-migration.md +0 -541
  51. package/lib/assets/docs/article/functional-desgin-ppp/clojure/index.md +0 -241
  52. package/lib/assets/docs/article/functional-desgin-ppp/elixir/01-immutability-and-data-transformation.md +0 -392
  53. package/lib/assets/docs/article/functional-desgin-ppp/elixir/02-function-composition.md +0 -383
  54. package/lib/assets/docs/article/functional-desgin-ppp/elixir/03-polymorphism.md +0 -384
  55. package/lib/assets/docs/article/functional-desgin-ppp/elixir/04-data-validation.md +0 -204
  56. package/lib/assets/docs/article/functional-desgin-ppp/elixir/05-property-based-testing.md +0 -277
  57. package/lib/assets/docs/article/functional-desgin-ppp/elixir/06-tdd-and-fp.md +0 -303
  58. package/lib/assets/docs/article/functional-desgin-ppp/elixir/07-effects-and-pure-functions.md +0 -173
  59. package/lib/assets/docs/article/functional-desgin-ppp/elixir/08-error-handling-strategies.md +0 -177
  60. package/lib/assets/docs/article/functional-desgin-ppp/elixir/09-io-and-external-systems.md +0 -263
  61. package/lib/assets/docs/article/functional-desgin-ppp/elixir/10-concurrency-patterns.md +0 -278
  62. package/lib/assets/docs/article/functional-desgin-ppp/elixir/11-command-pattern.md +0 -157
  63. package/lib/assets/docs/article/functional-desgin-ppp/elixir/12-visitor-pattern.md +0 -185
  64. package/lib/assets/docs/article/functional-desgin-ppp/elixir/13-abstract-factory-pattern.md +0 -613
  65. package/lib/assets/docs/article/functional-desgin-ppp/elixir/14-abstract-server-pattern.md +0 -738
  66. package/lib/assets/docs/article/functional-desgin-ppp/elixir/15-gossiping-bus-drivers.md +0 -300
  67. package/lib/assets/docs/article/functional-desgin-ppp/elixir/16-payroll-system.md +0 -429
  68. package/lib/assets/docs/article/functional-desgin-ppp/elixir/17-video-rental-system.md +0 -328
  69. package/lib/assets/docs/article/functional-desgin-ppp/elixir/18-concurrency-system.md +0 -475
  70. package/lib/assets/docs/article/functional-desgin-ppp/elixir/19-wator-simulation.md +0 -532
  71. package/lib/assets/docs/article/functional-desgin-ppp/elixir/20-pattern-interactions.md +0 -296
  72. package/lib/assets/docs/article/functional-desgin-ppp/elixir/21-best-practices.md +0 -349
  73. package/lib/assets/docs/article/functional-desgin-ppp/elixir/22-oo-to-fp-migration.md +0 -404
  74. package/lib/assets/docs/article/functional-desgin-ppp/elixir/index.md +0 -248
  75. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/01-immutability-and-data-transformation.md +0 -393
  76. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/02-function-composition.md +0 -461
  77. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/03-polymorphism.md +0 -504
  78. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/04-data-validation.md +0 -425
  79. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/05-property-based-testing.md +0 -391
  80. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/06-tdd-functional.md +0 -696
  81. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/07-composite-pattern.md +0 -451
  82. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/08-decorator-pattern.md +0 -488
  83. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/09-adapter-pattern.md +0 -488
  84. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/10-strategy-pattern.md +0 -436
  85. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/11-command-pattern.md +0 -437
  86. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/12-visitor-pattern.md +0 -348
  87. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/13-abstract-factory-pattern.md +0 -318
  88. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/14-abstract-server-pattern.md +0 -605
  89. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/15-gossiping-bus-drivers.md +0 -364
  90. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/16-payroll-system.md +0 -359
  91. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/17-video-rental-system.md +0 -423
  92. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/18-concurrency-system.md +0 -376
  93. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/19-wator-simulation.md +0 -412
  94. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/20-pattern-interactions.md +0 -300
  95. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/21-best-practices.md +0 -333
  96. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/22-oo-to-fp-migration.md +0 -341
  97. package/lib/assets/docs/article/functional-desgin-ppp/fsharp/index.md +0 -274
  98. package/lib/assets/docs/article/functional-desgin-ppp/haskell/01-immutability-and-data-transformation.md +0 -307
  99. package/lib/assets/docs/article/functional-desgin-ppp/haskell/02-function-composition.md +0 -313
  100. package/lib/assets/docs/article/functional-desgin-ppp/haskell/03-polymorphism.md +0 -371
  101. package/lib/assets/docs/article/functional-desgin-ppp/haskell/04-data-validation.md +0 -266
  102. package/lib/assets/docs/article/functional-desgin-ppp/haskell/05-property-based-testing.md +0 -263
  103. package/lib/assets/docs/article/functional-desgin-ppp/haskell/06-tdd-functional.md +0 -292
  104. package/lib/assets/docs/article/functional-desgin-ppp/haskell/07-composite-pattern.md +0 -404
  105. package/lib/assets/docs/article/functional-desgin-ppp/haskell/08-decorator-pattern.md +0 -328
  106. package/lib/assets/docs/article/functional-desgin-ppp/haskell/09-adapter-pattern.md +0 -391
  107. package/lib/assets/docs/article/functional-desgin-ppp/haskell/10-strategy-pattern.md +0 -296
  108. package/lib/assets/docs/article/functional-desgin-ppp/haskell/11-command-pattern.md +0 -312
  109. package/lib/assets/docs/article/functional-desgin-ppp/haskell/12-visitor-pattern.md +0 -335
  110. package/lib/assets/docs/article/functional-desgin-ppp/haskell/13-abstract-factory-pattern.md +0 -341
  111. package/lib/assets/docs/article/functional-desgin-ppp/haskell/14-abstract-server-pattern.md +0 -388
  112. package/lib/assets/docs/article/functional-desgin-ppp/haskell/15-gossiping-bus-drivers.md +0 -186
  113. package/lib/assets/docs/article/functional-desgin-ppp/haskell/16-payroll-system.md +0 -228
  114. package/lib/assets/docs/article/functional-desgin-ppp/haskell/17-video-rental-system.md +0 -253
  115. package/lib/assets/docs/article/functional-desgin-ppp/haskell/18-concurrency-system.md +0 -372
  116. package/lib/assets/docs/article/functional-desgin-ppp/haskell/19-wator-simulation.md +0 -447
  117. package/lib/assets/docs/article/functional-desgin-ppp/haskell/20-pattern-interactions.md +0 -334
  118. package/lib/assets/docs/article/functional-desgin-ppp/haskell/21-best-practices.md +0 -412
  119. package/lib/assets/docs/article/functional-desgin-ppp/haskell/22-oo-to-fp-migration.md +0 -478
  120. package/lib/assets/docs/article/functional-desgin-ppp/haskell/index.md +0 -174
  121. package/lib/assets/docs/article/functional-desgin-ppp/index.md +0 -90
  122. package/lib/assets/docs/article/functional-desgin-ppp/rust/01-immutability-and-data-transformation.md +0 -459
  123. package/lib/assets/docs/article/functional-desgin-ppp/rust/02-function-composition.md +0 -472
  124. package/lib/assets/docs/article/functional-desgin-ppp/rust/03-polymorphism.md +0 -434
  125. package/lib/assets/docs/article/functional-desgin-ppp/rust/04-data-validation.md +0 -282
  126. package/lib/assets/docs/article/functional-desgin-ppp/rust/05-property-based-testing.md +0 -256
  127. package/lib/assets/docs/article/functional-desgin-ppp/rust/06-tdd-and-functional.md +0 -850
  128. package/lib/assets/docs/article/functional-desgin-ppp/rust/07-composite-pattern.md +0 -393
  129. package/lib/assets/docs/article/functional-desgin-ppp/rust/08-decorator-pattern.md +0 -392
  130. package/lib/assets/docs/article/functional-desgin-ppp/rust/09-adapter-pattern.md +0 -348
  131. package/lib/assets/docs/article/functional-desgin-ppp/rust/10-strategy-pattern.md +0 -340
  132. package/lib/assets/docs/article/functional-desgin-ppp/rust/11-command-pattern.md +0 -365
  133. package/lib/assets/docs/article/functional-desgin-ppp/rust/12-visitor-pattern.md +0 -388
  134. package/lib/assets/docs/article/functional-desgin-ppp/rust/13-abstract-factory-pattern.md +0 -370
  135. package/lib/assets/docs/article/functional-desgin-ppp/rust/14-abstract-server-pattern.md +0 -401
  136. package/lib/assets/docs/article/functional-desgin-ppp/rust/15-gossiping-bus-drivers.md +0 -309
  137. package/lib/assets/docs/article/functional-desgin-ppp/rust/16-payroll-system.md +0 -306
  138. package/lib/assets/docs/article/functional-desgin-ppp/rust/17-video-rental-system.md +0 -313
  139. package/lib/assets/docs/article/functional-desgin-ppp/rust/18-concurrency-system.md +0 -324
  140. package/lib/assets/docs/article/functional-desgin-ppp/rust/19-wator-simulation.md +0 -320
  141. package/lib/assets/docs/article/functional-desgin-ppp/rust/20-pattern-interactions.md +0 -313
  142. package/lib/assets/docs/article/functional-desgin-ppp/rust/21-best-practices.md +0 -345
  143. package/lib/assets/docs/article/functional-desgin-ppp/rust/22-oo-to-fp-migration.md +0 -358
  144. package/lib/assets/docs/article/functional-desgin-ppp/rust/index.md +0 -243
  145. package/lib/assets/docs/article/functional-desgin-ppp/scala/01-immutability-and-data-transformation.md +0 -337
  146. package/lib/assets/docs/article/functional-desgin-ppp/scala/02-function-composition.md +0 -357
  147. package/lib/assets/docs/article/functional-desgin-ppp/scala/03-polymorphism.md +0 -366
  148. package/lib/assets/docs/article/functional-desgin-ppp/scala/04-data-validation.md +0 -373
  149. package/lib/assets/docs/article/functional-desgin-ppp/scala/05-property-based-testing.md +0 -524
  150. package/lib/assets/docs/article/functional-desgin-ppp/scala/06-tdd-functional.md +0 -566
  151. package/lib/assets/docs/article/functional-desgin-ppp/scala/07-composite-pattern.md +0 -372
  152. package/lib/assets/docs/article/functional-desgin-ppp/scala/08-decorator-pattern.md +0 -336
  153. package/lib/assets/docs/article/functional-desgin-ppp/scala/09-adapter-pattern.md +0 -526
  154. package/lib/assets/docs/article/functional-desgin-ppp/scala/10-strategy-pattern.md +0 -450
  155. package/lib/assets/docs/article/functional-desgin-ppp/scala/11-command-pattern.md +0 -416
  156. package/lib/assets/docs/article/functional-desgin-ppp/scala/12-visitor-pattern.md +0 -388
  157. package/lib/assets/docs/article/functional-desgin-ppp/scala/13-abstract-factory-pattern.md +0 -407
  158. package/lib/assets/docs/article/functional-desgin-ppp/scala/14-abstract-server-pattern.md +0 -485
  159. package/lib/assets/docs/article/functional-desgin-ppp/scala/15-gossiping-bus-drivers.md +0 -400
  160. package/lib/assets/docs/article/functional-desgin-ppp/scala/16-payroll-system.md +0 -351
  161. package/lib/assets/docs/article/functional-desgin-ppp/scala/17-video-rental-system.md +0 -333
  162. package/lib/assets/docs/article/functional-desgin-ppp/scala/18-concurrency-system.md +0 -739
  163. package/lib/assets/docs/article/functional-desgin-ppp/scala/19-wator-simulation.md +0 -633
  164. package/lib/assets/docs/article/functional-desgin-ppp/scala/20-pattern-interactions.md +0 -521
  165. package/lib/assets/docs/article/functional-desgin-ppp/scala/21-best-practices.md +0 -442
  166. package/lib/assets/docs/article/functional-desgin-ppp/scala/22-oo-to-fp-migration.md +0 -697
  167. package/lib/assets/docs/article/functional-desgin-ppp/scala/index.md +0 -243
  168. package/lib/assets/docs/article/getting-start-docker-kubernetes/01-container-and-docker-basics.md +0 -341
  169. package/lib/assets/docs/article/getting-start-docker-kubernetes/02-container-deployment.md +0 -785
  170. package/lib/assets/docs/article/getting-start-docker-kubernetes/03-practical-container-build-deploy.md +0 -466
  171. package/lib/assets/docs/article/getting-start-docker-kubernetes/04-multi-container-application.md +0 -878
  172. package/lib/assets/docs/article/getting-start-docker-kubernetes/05-kubernetes-introduction.md +0 -585
  173. package/lib/assets/docs/article/getting-start-docker-kubernetes/06-kubernetes-deploy-cluster.md +0 -620
  174. package/lib/assets/docs/article/getting-start-docker-kubernetes/07-kubernetes-advanced.md +0 -621
  175. package/lib/assets/docs/article/getting-start-docker-kubernetes/08-kubernetes-packaging.md +0 -518
  176. package/lib/assets/docs/article/getting-start-docker-kubernetes/09-container-operations.md +0 -546
  177. package/lib/assets/docs/article/getting-start-docker-kubernetes/10-optimal-container-image.md +0 -640
  178. package/lib/assets/docs/article/getting-start-docker-kubernetes/11-continuous-delivery.md +0 -607
  179. package/lib/assets/docs/article/getting-start-docker-kubernetes/12-container-use-cases.md +0 -463
  180. package/lib/assets/docs/article/getting-start-docker-kubernetes/13-case-monolith-compose-vs-kustomize.md +0 -346
  181. package/lib/assets/docs/article/getting-start-docker-kubernetes/14-case-event-driven-kustomize-vs-helm.md +0 -324
  182. package/lib/assets/docs/article/getting-start-docker-kubernetes/15-case-escqrs-axon-kustomize-vs-helm.md +0 -297
  183. package/lib/assets/docs/article/getting-start-docker-kubernetes/16-case-escqrs-kafka-kustomize-vs-helm.md +0 -256
  184. package/lib/assets/docs/article/getting-start-docker-kubernetes/17-case-comparison-summary.md +0 -141
  185. package/lib/assets/docs/article/getting-start-docker-kubernetes/18-case-load-testing.md +0 -303
  186. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-a-dev-tools-setup.md +0 -274
  187. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-b-orchestration-environments.md +0 -530
  188. package/lib/assets/docs/article/getting-start-docker-kubernetes/appendix-c-tips.md +0 -519
  189. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-01-comic.png +0 -0
  190. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-02-comic.png +0 -0
  191. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-03-comic.png +0 -0
  192. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-04-comic.png +0 -0
  193. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-05-comic.png +0 -0
  194. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-06-comic.png +0 -0
  195. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-07-comic.png +0 -0
  196. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-08-comic.png +0 -0
  197. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-09-comic.png +0 -0
  198. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-10-comic.png +0 -0
  199. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-11-comic.png +0 -0
  200. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/chapter-12-comic.png +0 -0
  201. package/lib/assets/docs/article/getting-start-docker-kubernetes/images/overview-comic.png +0 -0
  202. package/lib/assets/docs/article/getting-start-docker-kubernetes/index.md +0 -82
  203. package/lib/assets/docs/article/getting-start-docker-kubernetes/outline.md +0 -220
  204. package/lib/assets/docs/article/getting-start-tdd/clojure/01-todo-list-and-first-test.md +0 -175
  205. package/lib/assets/docs/article/getting-start-tdd/clojure/02-fake-it-and-triangulation.md +0 -171
  206. package/lib/assets/docs/article/getting-start-tdd/clojure/03-obvious-implementation-and-refactoring.md +0 -144
  207. package/lib/assets/docs/article/getting-start-tdd/clojure/04-version-control-and-conventional-commits.md +0 -97
  208. package/lib/assets/docs/article/getting-start-tdd/clojure/05-package-management-and-static-analysis.md +0 -308
  209. package/lib/assets/docs/article/getting-start-tdd/clojure/06-task-runner-and-ci-cd.md +0 -250
  210. package/lib/assets/docs/article/getting-start-tdd/clojure/07-protocols-and-records.md +0 -140
  211. package/lib/assets/docs/article/getting-start-tdd/clojure/08-multimethods-and-design-patterns.md +0 -139
  212. package/lib/assets/docs/article/getting-start-tdd/clojure/09-namespaces-and-module-design.md +0 -136
  213. package/lib/assets/docs/article/getting-start-tdd/clojure/10-higher-order-functions-and-composition.md +0 -123
  214. package/lib/assets/docs/article/getting-start-tdd/clojure/11-persistent-data-and-pipeline.md +0 -147
  215. package/lib/assets/docs/article/getting-start-tdd/clojure/12-error-handling-and-spec.md +0 -170
  216. package/lib/assets/docs/article/getting-start-tdd/clojure/index.md +0 -65
  217. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter01.md +0 -241
  218. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter02.md +0 -253
  219. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter03.md +0 -211
  220. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter04.md +0 -101
  221. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter05.md +0 -265
  222. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter06.md +0 -204
  223. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter07.md +0 -223
  224. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter08.md +0 -258
  225. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter09.md +0 -183
  226. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter10.md +0 -175
  227. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter11.md +0 -201
  228. package/lib/assets/docs/article/getting-start-tdd/csharp/chapter12.md +0 -220
  229. package/lib/assets/docs/article/getting-start-tdd/csharp/index.md +0 -83
  230. package/lib/assets/docs/article/getting-start-tdd/elixir/01-todo-list-and-first-test.md +0 -96
  231. package/lib/assets/docs/article/getting-start-tdd/elixir/02-fake-it-and-triangulation.md +0 -104
  232. package/lib/assets/docs/article/getting-start-tdd/elixir/03-obvious-implementation-and-refactoring.md +0 -118
  233. package/lib/assets/docs/article/getting-start-tdd/elixir/04-version-control-and-conventional-commits.md +0 -105
  234. package/lib/assets/docs/article/getting-start-tdd/elixir/05-package-management-and-static-analysis.md +0 -97
  235. package/lib/assets/docs/article/getting-start-tdd/elixir/06-task-runner-and-ci-cd.md +0 -80
  236. package/lib/assets/docs/article/getting-start-tdd/elixir/07-structs-and-protocols.md +0 -119
  237. package/lib/assets/docs/article/getting-start-tdd/elixir/08-pattern-matching-and-guards.md +0 -117
  238. package/lib/assets/docs/article/getting-start-tdd/elixir/09-module-design-and-behaviours.md +0 -113
  239. package/lib/assets/docs/article/getting-start-tdd/elixir/10-higher-order-functions-and-pipeline.md +0 -187
  240. package/lib/assets/docs/article/getting-start-tdd/elixir/11-stream-and-lazy-evaluation.md +0 -151
  241. package/lib/assets/docs/article/getting-start-tdd/elixir/12-error-handling-and-with.md +0 -154
  242. package/lib/assets/docs/article/getting-start-tdd/elixir/index.md +0 -35
  243. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter01.md +0 -211
  244. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter02.md +0 -255
  245. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter03.md +0 -227
  246. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter04.md +0 -188
  247. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter05.md +0 -276
  248. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter06.md +0 -199
  249. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter07.md +0 -170
  250. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter08.md +0 -184
  251. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter09.md +0 -231
  252. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter10.md +0 -198
  253. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter11.md +0 -221
  254. package/lib/assets/docs/article/getting-start-tdd/fsharp/chapter12.md +0 -224
  255. package/lib/assets/docs/article/getting-start-tdd/fsharp/index.md +0 -71
  256. package/lib/assets/docs/article/getting-start-tdd/go/01-todo-list-and-first-test.md +0 -222
  257. package/lib/assets/docs/article/getting-start-tdd/go/02-fake-it-and-triangulation.md +0 -311
  258. package/lib/assets/docs/article/getting-start-tdd/go/03-obvious-implementation-and-refactoring.md +0 -348
  259. package/lib/assets/docs/article/getting-start-tdd/go/04-version-control-and-conventional-commits.md +0 -121
  260. package/lib/assets/docs/article/getting-start-tdd/go/05-package-management-and-static-analysis.md +0 -281
  261. package/lib/assets/docs/article/getting-start-tdd/go/06-task-runner-and-ci-cd.md +0 -242
  262. package/lib/assets/docs/article/getting-start-tdd/go/07-encapsulation-and-polymorphism.md +0 -402
  263. package/lib/assets/docs/article/getting-start-tdd/go/08-design-patterns.md +0 -430
  264. package/lib/assets/docs/article/getting-start-tdd/go/09-solid-principles-and-module-design.md +0 -408
  265. package/lib/assets/docs/article/getting-start-tdd/go/10-higher-order-functions-and-composition.md +0 -234
  266. package/lib/assets/docs/article/getting-start-tdd/go/11-immutable-data-and-pipeline.md +0 -304
  267. package/lib/assets/docs/article/getting-start-tdd/go/12-error-handling-and-type-safety.md +0 -419
  268. package/lib/assets/docs/article/getting-start-tdd/go/index.md +0 -83
  269. package/lib/assets/docs/article/getting-start-tdd/haskell/01-todo-list-and-first-test.md +0 -288
  270. package/lib/assets/docs/article/getting-start-tdd/haskell/02-fake-it-and-triangulation.md +0 -346
  271. package/lib/assets/docs/article/getting-start-tdd/haskell/03-obvious-implementation-and-refactoring.md +0 -266
  272. package/lib/assets/docs/article/getting-start-tdd/haskell/04-version-control-and-conventional-commits.md +0 -191
  273. package/lib/assets/docs/article/getting-start-tdd/haskell/05-package-management-and-static-analysis.md +0 -322
  274. package/lib/assets/docs/article/getting-start-tdd/haskell/06-task-runner-and-ci-cd.md +0 -318
  275. package/lib/assets/docs/article/getting-start-tdd/haskell/07-algebraic-data-types-and-type-classes.md +0 -421
  276. package/lib/assets/docs/article/getting-start-tdd/haskell/08-pattern-matching-and-guards.md +0 -399
  277. package/lib/assets/docs/article/getting-start-tdd/haskell/09-module-design-and-smart-constructors.md +0 -470
  278. package/lib/assets/docs/article/getting-start-tdd/haskell/10-higher-order-functions-and-currying.md +0 -443
  279. package/lib/assets/docs/article/getting-start-tdd/haskell/11-function-composition-and-point-free.md +0 -401
  280. package/lib/assets/docs/article/getting-start-tdd/haskell/12-monad-and-error-handling.md +0 -640
  281. package/lib/assets/docs/article/getting-start-tdd/haskell/index.md +0 -49
  282. package/lib/assets/docs/article/getting-start-tdd/index.md +0 -93
  283. package/lib/assets/docs/article/getting-start-tdd/integration/01-language-overview.md +0 -384
  284. package/lib/assets/docs/article/getting-start-tdd/integration/02-test-framework-comparison.md +0 -358
  285. package/lib/assets/docs/article/getting-start-tdd/integration/03-tdd-pattern-comparison.md +0 -454
  286. package/lib/assets/docs/article/getting-start-tdd/integration/04-type-system-comparison.md +0 -418
  287. package/lib/assets/docs/article/getting-start-tdd/integration/05-dev-environment-comparison.md +0 -339
  288. package/lib/assets/docs/article/getting-start-tdd/integration/06-learning-roadmap.md +0 -299
  289. package/lib/assets/docs/article/getting-start-tdd/integration/index.md +0 -69
  290. package/lib/assets/docs/article/getting-start-tdd/java/01-todo-list-and-first-test.md +0 -243
  291. package/lib/assets/docs/article/getting-start-tdd/java/02-fake-it-and-triangulation.md +0 -270
  292. package/lib/assets/docs/article/getting-start-tdd/java/03-obvious-implementation-and-refactoring.md +0 -194
  293. package/lib/assets/docs/article/getting-start-tdd/java/04-version-control-and-conventional-commits.md +0 -124
  294. package/lib/assets/docs/article/getting-start-tdd/java/05-package-management-and-static-analysis.md +0 -391
  295. package/lib/assets/docs/article/getting-start-tdd/java/06-task-runner-and-ci-cd.md +0 -281
  296. package/lib/assets/docs/article/getting-start-tdd/java/07-encapsulation-and-polymorphism.md +0 -635
  297. package/lib/assets/docs/article/getting-start-tdd/java/08-design-patterns.md +0 -402
  298. package/lib/assets/docs/article/getting-start-tdd/java/09-solid-principles-and-module-design.md +0 -319
  299. package/lib/assets/docs/article/getting-start-tdd/java/10-higher-order-functions-and-composition.md +0 -197
  300. package/lib/assets/docs/article/getting-start-tdd/java/11-immutable-data-and-pipeline.md +0 -176
  301. package/lib/assets/docs/article/getting-start-tdd/java/12-error-handling-and-type-safety.md +0 -214
  302. package/lib/assets/docs/article/getting-start-tdd/java/index.md +0 -61
  303. package/lib/assets/docs/article/getting-start-tdd/node/01-todo-list-and-first-test.md +0 -253
  304. package/lib/assets/docs/article/getting-start-tdd/node/02-fake-it-and-triangulation.md +0 -271
  305. package/lib/assets/docs/article/getting-start-tdd/node/03-obvious-implementation-and-refactoring.md +0 -178
  306. package/lib/assets/docs/article/getting-start-tdd/node/04-version-control-and-conventional-commits.md +0 -121
  307. package/lib/assets/docs/article/getting-start-tdd/node/05-package-management-and-static-analysis.md +0 -323
  308. package/lib/assets/docs/article/getting-start-tdd/node/06-task-runner-and-ci-cd.md +0 -244
  309. package/lib/assets/docs/article/getting-start-tdd/node/07-encapsulation-and-polymorphism.md +0 -336
  310. package/lib/assets/docs/article/getting-start-tdd/node/08-design-patterns.md +0 -331
  311. package/lib/assets/docs/article/getting-start-tdd/node/09-solid-principles-and-module-design.md +0 -294
  312. package/lib/assets/docs/article/getting-start-tdd/node/10-higher-order-functions-and-composition.md +0 -208
  313. package/lib/assets/docs/article/getting-start-tdd/node/11-immutable-data-and-pipeline.md +0 -216
  314. package/lib/assets/docs/article/getting-start-tdd/node/12-error-handling-and-type-safety.md +0 -304
  315. package/lib/assets/docs/article/getting-start-tdd/node/index.md +0 -56
  316. package/lib/assets/docs/article/getting-start-tdd/php/01-todo-list-and-first-test.md +0 -268
  317. package/lib/assets/docs/article/getting-start-tdd/php/02-fake-it-and-triangulation.md +0 -209
  318. package/lib/assets/docs/article/getting-start-tdd/php/03-obvious-implementation-and-refactoring.md +0 -257
  319. package/lib/assets/docs/article/getting-start-tdd/php/04-version-control-and-conventional-commits.md +0 -150
  320. package/lib/assets/docs/article/getting-start-tdd/php/05-package-management-and-static-analysis.md +0 -419
  321. package/lib/assets/docs/article/getting-start-tdd/php/06-task-runner-and-ci-cd.md +0 -330
  322. package/lib/assets/docs/article/getting-start-tdd/php/07-encapsulation-and-polymorphism.md +0 -380
  323. package/lib/assets/docs/article/getting-start-tdd/php/08-design-patterns.md +0 -461
  324. package/lib/assets/docs/article/getting-start-tdd/php/09-solid-principles-and-module-design.md +0 -468
  325. package/lib/assets/docs/article/getting-start-tdd/php/10-higher-order-functions-and-composition.md +0 -190
  326. package/lib/assets/docs/article/getting-start-tdd/php/11-immutable-data-and-pipeline.md +0 -274
  327. package/lib/assets/docs/article/getting-start-tdd/php/12-error-handling-and-type-safety.md +0 -316
  328. package/lib/assets/docs/article/getting-start-tdd/php/index.md +0 -84
  329. package/lib/assets/docs/article/getting-start-tdd/python/01-todo-list-and-first-test.md +0 -210
  330. package/lib/assets/docs/article/getting-start-tdd/python/02-fake-it-and-triangulation.md +0 -256
  331. package/lib/assets/docs/article/getting-start-tdd/python/03-obvious-implementation-and-refactoring.md +0 -208
  332. package/lib/assets/docs/article/getting-start-tdd/python/04-version-control-and-conventional-commits.md +0 -96
  333. package/lib/assets/docs/article/getting-start-tdd/python/05-package-management-and-static-analysis.md +0 -283
  334. package/lib/assets/docs/article/getting-start-tdd/python/06-task-runner-and-ci-cd.md +0 -199
  335. package/lib/assets/docs/article/getting-start-tdd/python/07-encapsulation-and-polymorphism.md +0 -217
  336. package/lib/assets/docs/article/getting-start-tdd/python/08-design-patterns.md +0 -181
  337. package/lib/assets/docs/article/getting-start-tdd/python/09-solid-principles-and-module-design.md +0 -139
  338. package/lib/assets/docs/article/getting-start-tdd/python/10-higher-order-functions-and-composition.md +0 -131
  339. package/lib/assets/docs/article/getting-start-tdd/python/11-immutable-data-and-pipeline.md +0 -125
  340. package/lib/assets/docs/article/getting-start-tdd/python/12-error-handling-and-type-safety.md +0 -135
  341. package/lib/assets/docs/article/getting-start-tdd/python/index.md +0 -55
  342. package/lib/assets/docs/article/getting-start-tdd/ruby/01-todo-list-and-first-test.md +0 -240
  343. package/lib/assets/docs/article/getting-start-tdd/ruby/02-fake-it-and-triangulation.md +0 -247
  344. package/lib/assets/docs/article/getting-start-tdd/ruby/03-obvious-implementation-and-refactoring.md +0 -237
  345. package/lib/assets/docs/article/getting-start-tdd/ruby/04-version-control-and-conventional-commits.md +0 -121
  346. package/lib/assets/docs/article/getting-start-tdd/ruby/05-package-management-and-static-analysis.md +0 -296
  347. package/lib/assets/docs/article/getting-start-tdd/ruby/06-task-runner-and-ci-cd.md +0 -257
  348. package/lib/assets/docs/article/getting-start-tdd/ruby/07-encapsulation-and-polymorphism.md +0 -288
  349. package/lib/assets/docs/article/getting-start-tdd/ruby/08-design-patterns.md +0 -338
  350. package/lib/assets/docs/article/getting-start-tdd/ruby/09-solid-principles-and-module-design.md +0 -205
  351. package/lib/assets/docs/article/getting-start-tdd/ruby/10-higher-order-functions-and-composition.md +0 -184
  352. package/lib/assets/docs/article/getting-start-tdd/ruby/11-immutable-data-and-pipeline.md +0 -246
  353. package/lib/assets/docs/article/getting-start-tdd/ruby/12-error-handling-and-type-safety.md +0 -407
  354. package/lib/assets/docs/article/getting-start-tdd/ruby/index.md +0 -83
  355. package/lib/assets/docs/article/getting-start-tdd/rust/01-todo-list-and-first-test.md +0 -220
  356. package/lib/assets/docs/article/getting-start-tdd/rust/02-fake-it-and-triangulation.md +0 -273
  357. package/lib/assets/docs/article/getting-start-tdd/rust/03-obvious-implementation-and-refactoring.md +0 -242
  358. package/lib/assets/docs/article/getting-start-tdd/rust/04-version-control-and-conventional-commits.md +0 -101
  359. package/lib/assets/docs/article/getting-start-tdd/rust/05-package-management-and-static-analysis.md +0 -221
  360. package/lib/assets/docs/article/getting-start-tdd/rust/06-task-runner-and-ci-cd.md +0 -173
  361. package/lib/assets/docs/article/getting-start-tdd/rust/07-encapsulation-and-polymorphism.md +0 -151
  362. package/lib/assets/docs/article/getting-start-tdd/rust/08-design-patterns.md +0 -154
  363. package/lib/assets/docs/article/getting-start-tdd/rust/09-solid-principles-and-module-design.md +0 -119
  364. package/lib/assets/docs/article/getting-start-tdd/rust/10-higher-order-functions-and-composition.md +0 -103
  365. package/lib/assets/docs/article/getting-start-tdd/rust/11-immutable-data-and-pipeline.md +0 -114
  366. package/lib/assets/docs/article/getting-start-tdd/rust/12-error-handling-and-type-safety.md +0 -121
  367. package/lib/assets/docs/article/getting-start-tdd/rust/index.md +0 -83
  368. package/lib/assets/docs/article/getting-start-tdd/scala/01-todo-list-and-first-test.md +0 -120
  369. package/lib/assets/docs/article/getting-start-tdd/scala/02-fake-it-and-triangulation.md +0 -116
  370. package/lib/assets/docs/article/getting-start-tdd/scala/03-obvious-implementation-and-refactoring.md +0 -108
  371. package/lib/assets/docs/article/getting-start-tdd/scala/04-version-control-and-conventional-commits.md +0 -132
  372. package/lib/assets/docs/article/getting-start-tdd/scala/05-package-management-and-static-analysis.md +0 -205
  373. package/lib/assets/docs/article/getting-start-tdd/scala/06-task-runner-and-ci-cd.md +0 -195
  374. package/lib/assets/docs/article/getting-start-tdd/scala/07-case-classes-and-traits.md +0 -148
  375. package/lib/assets/docs/article/getting-start-tdd/scala/08-pattern-matching-and-sealed-traits.md +0 -115
  376. package/lib/assets/docs/article/getting-start-tdd/scala/09-packages-and-module-design.md +0 -84
  377. package/lib/assets/docs/article/getting-start-tdd/scala/10-higher-order-functions-and-composition.md +0 -113
  378. package/lib/assets/docs/article/getting-start-tdd/scala/11-collections-and-lazy-evaluation.md +0 -103
  379. package/lib/assets/docs/article/getting-start-tdd/scala/12-error-handling-and-type-safety.md +0 -101
  380. package/lib/assets/docs/article/getting-start-tdd/scala/index.md +0 -65
  381. package/lib/assets/docs/article/grokking-concurrency/all/index.md +0 -403
  382. package/lib/assets/docs/article/grokking-concurrency/all/part-1-ch02-sequential.md +0 -563
  383. package/lib/assets/docs/article/grokking-concurrency/all/part-2-ch04-05-threads.md +0 -478
  384. package/lib/assets/docs/article/grokking-concurrency/all/part-3-ch06-multitasking.md +0 -529
  385. package/lib/assets/docs/article/grokking-concurrency/all/part-4-ch07-parallel-patterns.md +0 -429
  386. package/lib/assets/docs/article/grokking-concurrency/all/part-5-ch08-09-synchronization.md +0 -519
  387. package/lib/assets/docs/article/grokking-concurrency/all/part-6-ch10-11-nonblocking-io.md +0 -444
  388. package/lib/assets/docs/article/grokking-concurrency/all/part-7-ch12-async.md +0 -474
  389. package/lib/assets/docs/article/grokking-concurrency/all/part-8-ch13-mapreduce.md +0 -386
  390. package/lib/assets/docs/article/grokking-concurrency/clojure/index.md +0 -106
  391. package/lib/assets/docs/article/grokking-concurrency/clojure/part-1.md +0 -107
  392. package/lib/assets/docs/article/grokking-concurrency/clojure/part-2.md +0 -100
  393. package/lib/assets/docs/article/grokking-concurrency/clojure/part-3.md +0 -121
  394. package/lib/assets/docs/article/grokking-concurrency/clojure/part-4.md +0 -122
  395. package/lib/assets/docs/article/grokking-concurrency/clojure/part-5.md +0 -117
  396. package/lib/assets/docs/article/grokking-concurrency/clojure/part-6.md +0 -88
  397. package/lib/assets/docs/article/grokking-concurrency/clojure/part-7.md +0 -99
  398. package/lib/assets/docs/article/grokking-concurrency/clojure/part-8.md +0 -119
  399. package/lib/assets/docs/article/grokking-concurrency/csharp/index.md +0 -91
  400. package/lib/assets/docs/article/grokking-concurrency/csharp/part-1.md +0 -96
  401. package/lib/assets/docs/article/grokking-concurrency/csharp/part-2.md +0 -122
  402. package/lib/assets/docs/article/grokking-concurrency/csharp/part-3.md +0 -100
  403. package/lib/assets/docs/article/grokking-concurrency/csharp/part-4.md +0 -111
  404. package/lib/assets/docs/article/grokking-concurrency/csharp/part-5.md +0 -98
  405. package/lib/assets/docs/article/grokking-concurrency/csharp/part-6.md +0 -60
  406. package/lib/assets/docs/article/grokking-concurrency/csharp/part-7.md +0 -83
  407. package/lib/assets/docs/article/grokking-concurrency/csharp/part-8.md +0 -91
  408. package/lib/assets/docs/article/grokking-concurrency/fsharp/index.md +0 -55
  409. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-1.md +0 -79
  410. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-2.md +0 -102
  411. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-3.md +0 -93
  412. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-4.md +0 -109
  413. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-5.md +0 -103
  414. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-6.md +0 -92
  415. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-7.md +0 -120
  416. package/lib/assets/docs/article/grokking-concurrency/fsharp/part-8.md +0 -106
  417. package/lib/assets/docs/article/grokking-concurrency/haskell/index.md +0 -238
  418. package/lib/assets/docs/article/grokking-concurrency/haskell/part-1.md +0 -95
  419. package/lib/assets/docs/article/grokking-concurrency/haskell/part-2.md +0 -95
  420. package/lib/assets/docs/article/grokking-concurrency/haskell/part-3.md +0 -90
  421. package/lib/assets/docs/article/grokking-concurrency/haskell/part-4.md +0 -105
  422. package/lib/assets/docs/article/grokking-concurrency/haskell/part-5.md +0 -98
  423. package/lib/assets/docs/article/grokking-concurrency/haskell/part-6.md +0 -94
  424. package/lib/assets/docs/article/grokking-concurrency/haskell/part-7.md +0 -110
  425. package/lib/assets/docs/article/grokking-concurrency/haskell/part-8.md +0 -117
  426. package/lib/assets/docs/article/grokking-concurrency/index.md +0 -66
  427. package/lib/assets/docs/article/grokking-concurrency/java/index.md +0 -92
  428. package/lib/assets/docs/article/grokking-concurrency/java/part-1.md +0 -307
  429. package/lib/assets/docs/article/grokking-concurrency/java/part-2.md +0 -333
  430. package/lib/assets/docs/article/grokking-concurrency/java/part-3.md +0 -220
  431. package/lib/assets/docs/article/grokking-concurrency/java/part-4.md +0 -212
  432. package/lib/assets/docs/article/grokking-concurrency/java/part-5.md +0 -111
  433. package/lib/assets/docs/article/grokking-concurrency/java/part-6.md +0 -68
  434. package/lib/assets/docs/article/grokking-concurrency/java/part-7.md +0 -100
  435. package/lib/assets/docs/article/grokking-concurrency/java/part-8.md +0 -100
  436. package/lib/assets/docs/article/grokking-concurrency/python/index.md +0 -303
  437. package/lib/assets/docs/article/grokking-concurrency/python/part-1.md +0 -238
  438. package/lib/assets/docs/article/grokking-concurrency/python/part-2.md +0 -417
  439. package/lib/assets/docs/article/grokking-concurrency/python/part-3.md +0 -226
  440. package/lib/assets/docs/article/grokking-concurrency/python/part-4.md +0 -298
  441. package/lib/assets/docs/article/grokking-concurrency/python/part-5.md +0 -314
  442. package/lib/assets/docs/article/grokking-concurrency/python/part-6.md +0 -296
  443. package/lib/assets/docs/article/grokking-concurrency/python/part-7.md +0 -313
  444. package/lib/assets/docs/article/grokking-concurrency/python/part-8.md +0 -359
  445. package/lib/assets/docs/article/grokking-concurrency/rust/index.md +0 -260
  446. package/lib/assets/docs/article/grokking-concurrency/rust/part-1.md +0 -107
  447. package/lib/assets/docs/article/grokking-concurrency/rust/part-2.md +0 -119
  448. package/lib/assets/docs/article/grokking-concurrency/rust/part-3.md +0 -125
  449. package/lib/assets/docs/article/grokking-concurrency/rust/part-4.md +0 -174
  450. package/lib/assets/docs/article/grokking-concurrency/rust/part-5.md +0 -157
  451. package/lib/assets/docs/article/grokking-concurrency/rust/part-6.md +0 -93
  452. package/lib/assets/docs/article/grokking-concurrency/rust/part-7.md +0 -132
  453. package/lib/assets/docs/article/grokking-concurrency/rust/part-8.md +0 -154
  454. package/lib/assets/docs/article/grokking-concurrency/scala/index.md +0 -59
  455. package/lib/assets/docs/article/grokking-concurrency/scala/part-1.md +0 -77
  456. package/lib/assets/docs/article/grokking-concurrency/scala/part-2.md +0 -111
  457. package/lib/assets/docs/article/grokking-concurrency/scala/part-3.md +0 -92
  458. package/lib/assets/docs/article/grokking-concurrency/scala/part-4.md +0 -109
  459. package/lib/assets/docs/article/grokking-concurrency/scala/part-5.md +0 -118
  460. package/lib/assets/docs/article/grokking-concurrency/scala/part-6.md +0 -82
  461. package/lib/assets/docs/article/grokking-concurrency/scala/part-7.md +0 -130
  462. package/lib/assets/docs/article/grokking-concurrency/scala/part-8.md +0 -128
  463. package/lib/assets/docs/article/grokkingfp/all/index.md +0 -368
  464. package/lib/assets/docs/article/grokkingfp/all/part-1-ch01-fp-introduction.md +0 -539
  465. package/lib/assets/docs/article/grokkingfp/all/part-1-ch02-pure-functions.md +0 -932
  466. package/lib/assets/docs/article/grokkingfp/all/part-2-ch03-immutable-data.md +0 -1137
  467. package/lib/assets/docs/article/grokkingfp/all/part-2-ch04-higher-order-functions.md +0 -1113
  468. package/lib/assets/docs/article/grokkingfp/all/part-2-ch05-flatmap.md +0 -1035
  469. package/lib/assets/docs/article/grokkingfp/all/part-3-ch06-option.md +0 -794
  470. package/lib/assets/docs/article/grokkingfp/all/part-3-ch07-either-adt.md +0 -880
  471. package/lib/assets/docs/article/grokkingfp/all/part-4-ch08-io-monad.md +0 -981
  472. package/lib/assets/docs/article/grokkingfp/all/part-4-ch09-streams.md +0 -935
  473. package/lib/assets/docs/article/grokkingfp/all/part-5-ch10-concurrency.md +0 -879
  474. package/lib/assets/docs/article/grokkingfp/all/part-6-ch11-application.md +0 -724
  475. package/lib/assets/docs/article/grokkingfp/all/part-6-ch12-testing.md +0 -635
  476. package/lib/assets/docs/article/grokkingfp/all/writing-plan.md +0 -721
  477. package/lib/assets/docs/article/grokkingfp/clojure/index.md +0 -276
  478. package/lib/assets/docs/article/grokkingfp/clojure/part-1.md +0 -676
  479. package/lib/assets/docs/article/grokkingfp/clojure/part-2.md +0 -652
  480. package/lib/assets/docs/article/grokkingfp/clojure/part-3.md +0 -629
  481. package/lib/assets/docs/article/grokkingfp/clojure/part-4.md +0 -706
  482. package/lib/assets/docs/article/grokkingfp/clojure/part-5.md +0 -760
  483. package/lib/assets/docs/article/grokkingfp/clojure/part-6.md +0 -730
  484. package/lib/assets/docs/article/grokkingfp/csharp/index.md +0 -246
  485. package/lib/assets/docs/article/grokkingfp/csharp/part-1.md +0 -820
  486. package/lib/assets/docs/article/grokkingfp/csharp/part-2.md +0 -980
  487. package/lib/assets/docs/article/grokkingfp/csharp/part-3.md +0 -990
  488. package/lib/assets/docs/article/grokkingfp/csharp/part-4.md +0 -958
  489. package/lib/assets/docs/article/grokkingfp/csharp/part-5.md +0 -956
  490. package/lib/assets/docs/article/grokkingfp/csharp/part-6.md +0 -748
  491. package/lib/assets/docs/article/grokkingfp/elixir/index.md +0 -203
  492. package/lib/assets/docs/article/grokkingfp/elixir/part-1.md +0 -721
  493. package/lib/assets/docs/article/grokkingfp/elixir/part-2.md +0 -847
  494. package/lib/assets/docs/article/grokkingfp/elixir/part-3.md +0 -994
  495. package/lib/assets/docs/article/grokkingfp/elixir/part-4.md +0 -983
  496. package/lib/assets/docs/article/grokkingfp/elixir/part-5.md +0 -1295
  497. package/lib/assets/docs/article/grokkingfp/elixir/part-6.md +0 -1058
  498. package/lib/assets/docs/article/grokkingfp/fsharp/index.md +0 -210
  499. package/lib/assets/docs/article/grokkingfp/fsharp/part-1.md +0 -723
  500. package/lib/assets/docs/article/grokkingfp/fsharp/part-2.md +0 -970
  501. package/lib/assets/docs/article/grokkingfp/fsharp/part-3.md +0 -981
  502. package/lib/assets/docs/article/grokkingfp/fsharp/part-4.md +0 -841
  503. package/lib/assets/docs/article/grokkingfp/fsharp/part-5.md +0 -920
  504. package/lib/assets/docs/article/grokkingfp/fsharp/part-6.md +0 -931
  505. package/lib/assets/docs/article/grokkingfp/haskell/index.md +0 -234
  506. package/lib/assets/docs/article/grokkingfp/haskell/part-1.md +0 -600
  507. package/lib/assets/docs/article/grokkingfp/haskell/part-2.md +0 -875
  508. package/lib/assets/docs/article/grokkingfp/haskell/part-3.md +0 -924
  509. package/lib/assets/docs/article/grokkingfp/haskell/part-4.md +0 -887
  510. package/lib/assets/docs/article/grokkingfp/haskell/part-5.md +0 -854
  511. package/lib/assets/docs/article/grokkingfp/haskell/part-6.md +0 -853
  512. package/lib/assets/docs/article/grokkingfp/index.md +0 -143
  513. package/lib/assets/docs/article/grokkingfp/java/index.md +0 -211
  514. package/lib/assets/docs/article/grokkingfp/java/part-1.md +0 -657
  515. package/lib/assets/docs/article/grokkingfp/java/part-2.md +0 -684
  516. package/lib/assets/docs/article/grokkingfp/java/part-3.md +0 -681
  517. package/lib/assets/docs/article/grokkingfp/java/part-4.md +0 -780
  518. package/lib/assets/docs/article/grokkingfp/java/part-5.md +0 -968
  519. package/lib/assets/docs/article/grokkingfp/java/part-6.md +0 -1337
  520. package/lib/assets/docs/article/grokkingfp/python/index.md +0 -258
  521. package/lib/assets/docs/article/grokkingfp/python/part-1.md +0 -452
  522. package/lib/assets/docs/article/grokkingfp/python/part-2.md +0 -967
  523. package/lib/assets/docs/article/grokkingfp/python/part-3.md +0 -1013
  524. package/lib/assets/docs/article/grokkingfp/python/part-4.md +0 -774
  525. package/lib/assets/docs/article/grokkingfp/python/part-5.md +0 -756
  526. package/lib/assets/docs/article/grokkingfp/python/part-6.md +0 -870
  527. package/lib/assets/docs/article/grokkingfp/ruby/index.md +0 -330
  528. package/lib/assets/docs/article/grokkingfp/ruby/part-1.md +0 -764
  529. package/lib/assets/docs/article/grokkingfp/ruby/part-2.md +0 -947
  530. package/lib/assets/docs/article/grokkingfp/ruby/part-3.md +0 -955
  531. package/lib/assets/docs/article/grokkingfp/ruby/part-4.md +0 -930
  532. package/lib/assets/docs/article/grokkingfp/ruby/part-5.md +0 -917
  533. package/lib/assets/docs/article/grokkingfp/ruby/part-6.md +0 -1421
  534. package/lib/assets/docs/article/grokkingfp/rust/index.md +0 -242
  535. package/lib/assets/docs/article/grokkingfp/rust/part-1.md +0 -643
  536. package/lib/assets/docs/article/grokkingfp/rust/part-2.md +0 -1069
  537. package/lib/assets/docs/article/grokkingfp/rust/part-3.md +0 -1003
  538. package/lib/assets/docs/article/grokkingfp/rust/part-4.md +0 -582
  539. package/lib/assets/docs/article/grokkingfp/rust/part-5.md +0 -714
  540. package/lib/assets/docs/article/grokkingfp/rust/part-6.md +0 -517
  541. package/lib/assets/docs/article/grokkingfp/scala/index.md +0 -171
  542. package/lib/assets/docs/article/grokkingfp/scala/part-1.md +0 -552
  543. package/lib/assets/docs/article/grokkingfp/scala/part-2.md +0 -955
  544. package/lib/assets/docs/article/grokkingfp/scala/part-3.md +0 -928
  545. package/lib/assets/docs/article/grokkingfp/scala/part-4.md +0 -751
  546. package/lib/assets/docs/article/grokkingfp/scala/part-5.md +0 -731
  547. package/lib/assets/docs/article/grokkingfp/scala/part-6.md +0 -876
  548. package/lib/assets/docs/article/grokkingfp/typescript/index.md +0 -273
  549. package/lib/assets/docs/article/grokkingfp/typescript/part-1.md +0 -570
  550. package/lib/assets/docs/article/grokkingfp/typescript/part-2.md +0 -1138
  551. package/lib/assets/docs/article/grokkingfp/typescript/part-3.md +0 -851
  552. package/lib/assets/docs/article/grokkingfp/typescript/part-4.md +0 -1096
  553. package/lib/assets/docs/article/grokkingfp/typescript/part-5.md +0 -726
  554. package/lib/assets/docs/article/grokkingfp/typescript/part-6.md +0 -991
  555. package/lib/assets/docs/article/practical-database-design/index.md +0 -121
  556. package/lib/assets/docs/article/practical-database-design/part1/chapter01.md +0 -297
  557. package/lib/assets/docs/article/practical-database-design/part1/chapter02.md +0 -527
  558. package/lib/assets/docs/article/practical-database-design/part1/chapter03.md +0 -566
  559. package/lib/assets/docs/article/practical-database-design/part2/chapter04.md +0 -933
  560. package/lib/assets/docs/article/practical-database-design/part2/chapter05.md +0 -1636
  561. package/lib/assets/docs/article/practical-database-design/part2/chapter06.md +0 -2725
  562. package/lib/assets/docs/article/practical-database-design/part2/chapter07.md +0 -2091
  563. package/lib/assets/docs/article/practical-database-design/part2/chapter08.md +0 -2114
  564. package/lib/assets/docs/article/practical-database-design/part2/chapter09.md +0 -2040
  565. package/lib/assets/docs/article/practical-database-design/part2/chapter10.md +0 -1396
  566. package/lib/assets/docs/article/practical-database-design/part2/chapter11.md +0 -1686
  567. package/lib/assets/docs/article/practical-database-design/part2/chapter12.md +0 -1426
  568. package/lib/assets/docs/article/practical-database-design/part2/chapter13.md +0 -1443
  569. package/lib/assets/docs/article/practical-database-design/part3/chapter14.md +0 -676
  570. package/lib/assets/docs/article/practical-database-design/part3/chapter15.md +0 -1634
  571. package/lib/assets/docs/article/practical-database-design/part3/chapter16.md +0 -1924
  572. package/lib/assets/docs/article/practical-database-design/part3/chapter17.md +0 -1717
  573. package/lib/assets/docs/article/practical-database-design/part3/chapter18.md +0 -2104
  574. package/lib/assets/docs/article/practical-database-design/part3/chapter19.md +0 -1132
  575. package/lib/assets/docs/article/practical-database-design/part3/chapter20.md +0 -1040
  576. package/lib/assets/docs/article/practical-database-design/part3/chapter21.md +0 -1391
  577. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter14-orm.md +0 -1000
  578. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter15-orm.md +0 -1309
  579. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter16-orm.md +0 -1175
  580. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter17-orm.md +0 -1593
  581. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter18-orm.md +0 -1192
  582. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter19-orm.md +0 -1025
  583. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter20-orm.md +0 -1762
  584. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter21-orm.md +0 -1456
  585. package/lib/assets/docs/article/practical-database-design/part3-orm/chapter22-orm.md +0 -1887
  586. package/lib/assets/docs/article/practical-database-design/part4/chapter22.md +0 -974
  587. package/lib/assets/docs/article/practical-database-design/part4/chapter23.md +0 -2078
  588. package/lib/assets/docs/article/practical-database-design/part4/chapter24.md +0 -2448
  589. package/lib/assets/docs/article/practical-database-design/part4/chapter25.md +0 -3670
  590. package/lib/assets/docs/article/practical-database-design/part4/chapter26.md +0 -2925
  591. package/lib/assets/docs/article/practical-database-design/part4/chapter27.md +0 -3114
  592. package/lib/assets/docs/article/practical-database-design/part4/chapter28.md +0 -2706
  593. package/lib/assets/docs/article/practical-database-design/part4/chapter29.md +0 -2552
  594. package/lib/assets/docs/article/practical-database-design/part4/chapter30.md +0 -2188
  595. package/lib/assets/docs/article/practical-database-design/part4/chapter31.md +0 -1200
  596. package/lib/assets/docs/article/practical-database-design/part4/chapter32.md +0 -2109
  597. package/lib/assets/docs/article/practical-database-design/part5/chapter33.md +0 -1041
  598. package/lib/assets/docs/article/practical-database-design/part5/chapter34.md +0 -1618
  599. package/lib/assets/docs/article/practical-database-design/part5/chapter35.md +0 -1462
  600. package/lib/assets/docs/article/practical-database-design/part5/chapter36.md +0 -1301
  601. package/lib/assets/docs/article/practical-database-design/part5/chapter37.md +0 -1479
  602. package/lib/assets/docs/article/practical-database-design/part5/chapter38.md +0 -1707
  603. package/lib/assets/docs/article/practical-database-design/part5/chapter39.md +0 -2343
  604. package/lib/assets/docs/article/practical-database-design/study/study2-1.md +0 -1702
  605. package/lib/assets/docs/article/practical-database-design/study/study2-2.md +0 -1356
  606. package/lib/assets/docs/article/practical-database-design/study/study2-3.md +0 -2053
  607. package/lib/assets/docs/article/practical-database-design/study/study2-4.md +0 -2238
  608. package/lib/assets/docs/article/practical-database-design/study/study2-5.md +0 -2427
  609. package/lib/assets/docs/article/practical-database-design/study/study3-1.md +0 -2214
  610. package/lib/assets/docs/article/practical-database-design/study/study3-2.md +0 -2230
  611. package/lib/assets/docs/article/practical-database-design/study/study3-3.md +0 -2262
  612. package/lib/assets/docs/article/practical-database-design/study/study3-4.md +0 -2115
  613. package/lib/assets/docs/article/practical-database-design/study/study3-5.md +0 -2516
  614. package/lib/assets/docs/article/practical-database-design/study/study4-1.md +0 -2596
  615. package/lib/assets/docs/article/practical-database-design/study/study4-2.md +0 -2084
  616. package/lib/assets/docs/article/practical-database-design/study/study4-3.md +0 -1814
  617. package/lib/assets/docs/article/practical-database-design/study/study4-4.md +0 -1904
  618. package/lib/assets/docs/article/practical-database-design/study/study4-5.md +0 -2887
@@ -1,2725 +0,0 @@
1
- ---
2
- type: Article
3
- title: "第6章:受注・出荷・売上の設計"
4
- description: "販売管理システムの中核となるトランザクションデータを設計していきます。"
5
- tags: [article, practical-database-design, part2]
6
- status: stable
7
- generated: { by: human:kakimomokuri, at: 2026-03-30T08:34:28Z }
8
- ---
9
-
10
- # 第6章:受注・出荷・売上の設計
11
-
12
- 販売管理システムの中核となるトランザクションデータを設計していきます。本章では、受注から出荷、売上計上までの一連の業務フローに対応したデータベース設計と実装を行います。
13
-
14
- ## 販売業務の全体フロー
15
-
16
- 販売業務は「見積 → 受注 → 出荷 → 売上」という一連のフローで構成されます。
17
-
18
- ```plantuml
19
- @startuml
20
-
21
- title 販売業務フロー
22
-
23
- |営業部門|
24
- start
25
- :見積作成;
26
- note right
27
- 顧客からの問い合わせに
28
- 対して見積書を作成
29
- end note
30
-
31
- :見積提出;
32
-
33
- if (受注確定?) then (yes)
34
- :受注登録;
35
- else (no)
36
- :失注処理;
37
- stop
38
- endif
39
-
40
- |倉庫部門|
41
- :出荷指示;
42
- note right
43
- 受注データを元に
44
- 出荷指示を作成
45
- end note
46
-
47
- :ピッキング;
48
- :検品・梱包;
49
- :出荷;
50
-
51
- |営業部門|
52
- :売上計上;
53
- note right
54
- 出荷完了時点で
55
- 売上を計上
56
- end note
57
-
58
- :納品書発行;
59
- stop
60
-
61
- @enduml
62
- ```
63
-
64
- ### トランザクションデータの特徴
65
-
66
- トランザクションデータには以下の共通した特徴があります。
67
-
68
- | 特徴 | 説明 |
69
- |-----|------|
70
- | **ヘッダ・明細構造** | 1つの取引に複数の商品が含まれるため、ヘッダ(親)と明細(子)の構造を持つ |
71
- | **ステータス管理** | 業務の進捗状態を管理するステータスを持つ |
72
- | **連番管理** | 伝票番号などの連番を自動採番する |
73
- | **日時管理** | 作成日時、更新日時など監査証跡を残す |
74
- | **マスタ参照** | 顧客・商品・社員などのマスタを参照する |
75
-
76
- ---
77
-
78
- ## 6.1 受注業務の DB 設計
79
-
80
- ### 受注業務フローの理解
81
-
82
- 受注業務は、顧客からの注文を受け付け、システムに登録する業務です。
83
-
84
- ```plantuml
85
- @startuml
86
-
87
- title 受注業務フロー
88
-
89
- |営業担当|
90
- start
91
- :見積書を確認;
92
-
93
- if (見積あり?) then (yes)
94
- :見積から受注へ変換;
95
- else (no)
96
- :新規受注入力;
97
- endif
98
-
99
- :受注データ登録;
100
- note right
101
- 顧客情報
102
- 商品・数量・単価
103
- 納期
104
- 配送先
105
- end note
106
-
107
- :受注明細登録;
108
-
109
- :受注確認書発行;
110
-
111
- |倉庫担当|
112
- :在庫引当;
113
- note right
114
- 受注数量分の
115
- 在庫を確保
116
- end note
117
-
118
- if (在庫あり?) then (yes)
119
- :引当完了;
120
- else (no)
121
- :入荷待ち;
122
- endif
123
-
124
- stop
125
-
126
- @enduml
127
- ```
128
-
129
- ### 受注データ・受注明細データの構造
130
-
131
- #### 受注データの ER 図
132
-
133
- ```plantuml
134
- @startuml
135
-
136
- title 受注関連テーブル
137
-
138
- entity 見積データ {
139
- ID <<PK>>
140
- --
141
- 見積番号 <<UK>>
142
- 見積日
143
- 見積有効期限
144
- 顧客コード <<FK>>
145
- 顧客枝番 <<FK>>
146
- 担当者コード
147
- 件名
148
- 見積金額
149
- 消費税額
150
- 見積合計
151
- ステータス
152
- 備考
153
- 作成日時
154
- 更新日時
155
- }
156
-
157
- entity 見積明細 {
158
- ID <<PK>>
159
- --
160
- 見積ID <<FK>>
161
- 行番号
162
- 商品コード <<FK>>
163
- 商品名
164
- 数量
165
- 単位
166
- 単価
167
- 金額
168
- 税区分
169
- 消費税率
170
- 消費税額
171
- 備考
172
- }
173
-
174
- entity 受注データ {
175
- ID <<PK>>
176
- --
177
- 受注番号 <<UK>>
178
- 受注日
179
- 顧客コード <<FK>>
180
- 顧客枝番 <<FK>>
181
- 出荷先番号 <<FK>>
182
- 担当者コード
183
- 希望納期
184
- 出荷予定日
185
- 受注金額
186
- 消費税額
187
- 受注合計
188
- ステータス
189
- 見積ID <<FK>>
190
- 顧客注文番号
191
- 備考
192
- 作成日時
193
- 更新日時
194
- }
195
-
196
- entity 受注明細 {
197
- ID <<PK>>
198
- --
199
- 受注ID <<FK>>
200
- 行番号
201
- 商品コード <<FK>>
202
- 商品名
203
- 受注数量
204
- 引当数量
205
- 出荷数量
206
- 残数量
207
- 単位
208
- 単価
209
- 金額
210
- 税区分
211
- 消費税率
212
- 消費税額
213
- 倉庫コード
214
- 希望納期
215
- 備考
216
- }
217
-
218
- 見積データ ||--o{ 見積明細
219
- 見積データ ||--o| 受注データ : "受注化"
220
- 受注データ ||--o{ 受注明細
221
-
222
- @enduml
223
- ```
224
-
225
- ### 受注ステータスの定義
226
-
227
- ```plantuml
228
- @startuml
229
-
230
- title 受注ステータス遷移図
231
-
232
- [*] --> 受付済
233
-
234
- 受付済 --> 引当済 : 在庫引当完了
235
- 受付済 --> 出荷指示済 : 出荷指示作成
236
-
237
- 引当済 --> 出荷指示済 : 出荷指示作成
238
-
239
- 出荷指示済 --> 出荷済 : 出荷完了
240
-
241
- 出荷済 --> [*]
242
-
243
- 受付済 --> キャンセル
244
- 引当済 --> キャンセル
245
- 出荷指示済 --> キャンセル
246
-
247
- キャンセル --> [*]
248
-
249
- @enduml
250
- ```
251
-
252
- | ステータス | 説明 |
253
- |-----------|------|
254
- | **受付済** | 受注登録が完了した状態 |
255
- | **引当済** | 在庫引当が完了した状態 |
256
- | **出荷指示済** | 出荷指示が作成された状態 |
257
- | **出荷済** | 出荷が完了した状態 |
258
- | **キャンセル** | 受注がキャンセルされた状態 |
259
-
260
- ### マイグレーション:受注関連テーブルの作成
261
-
262
- <details>
263
- <summary>V007__create_quotation_order_tables.sql</summary>
264
-
265
- ```sql
266
- -- src/main/resources/db/migration/V007__create_quotation_order_tables.sql
267
-
268
- -- 見積ステータス
269
- CREATE TYPE 見積ステータス AS ENUM ('商談中', '受注確定', '失注', '期限切れ');
270
-
271
- -- 受注ステータス
272
- CREATE TYPE 受注ステータス AS ENUM ('受付済', '引当済', '出荷指示済', '出荷済', 'キャンセル');
273
-
274
- -- 見積データ(ヘッダ)
275
- CREATE TABLE "見積データ" (
276
- "ID" SERIAL PRIMARY KEY,
277
- "見積番号" VARCHAR(20) UNIQUE NOT NULL,
278
- "見積日" DATE NOT NULL,
279
- "見積有効期限" DATE,
280
- "顧客コード" VARCHAR(20) NOT NULL,
281
- "顧客枝番" VARCHAR(10) DEFAULT '00',
282
- "担当者コード" VARCHAR(20),
283
- "件名" VARCHAR(200),
284
- "見積金額" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
285
- "消費税額" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
286
- "見積合計" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
287
- "ステータス" 見積ステータス DEFAULT '商談中' NOT NULL,
288
- "備考" TEXT,
289
- "作成日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
290
- "作成者" VARCHAR(50),
291
- "更新日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
292
- "更新者" VARCHAR(50),
293
- CONSTRAINT "fk_見積データ_顧客"
294
- FOREIGN KEY ("顧客コード", "顧客枝番") REFERENCES "顧客マスタ"("顧客コード", "顧客枝番")
295
- );
296
-
297
- -- 見積明細
298
- CREATE TABLE "見積明細" (
299
- "ID" SERIAL PRIMARY KEY,
300
- "見積ID" INTEGER NOT NULL,
301
- "行番号" INTEGER NOT NULL,
302
- "商品コード" VARCHAR(20) NOT NULL,
303
- "商品名" VARCHAR(100) NOT NULL,
304
- "数量" DECIMAL(15, 2) NOT NULL,
305
- "単位" VARCHAR(10),
306
- "単価" DECIMAL(15, 2) NOT NULL,
307
- "金額" DECIMAL(15, 2) NOT NULL,
308
- "税区分" 税区分 DEFAULT '外税' NOT NULL,
309
- "消費税率" DECIMAL(5, 2) DEFAULT 10.00 NOT NULL,
310
- "消費税額" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
311
- "備考" TEXT,
312
- CONSTRAINT "fk_見積明細_見積"
313
- FOREIGN KEY ("見積ID") REFERENCES "見積データ"("ID") ON DELETE CASCADE,
314
- CONSTRAINT "fk_見積明細_商品"
315
- FOREIGN KEY ("商品コード") REFERENCES "商品マスタ"("商品コード"),
316
- CONSTRAINT "uq_見積明細_行番号" UNIQUE ("見積ID", "行番号")
317
- );
318
-
319
- -- 受注データ(ヘッダ)
320
- CREATE TABLE "受注データ" (
321
- "ID" SERIAL PRIMARY KEY,
322
- "受注番号" VARCHAR(20) UNIQUE NOT NULL,
323
- "受注日" DATE NOT NULL,
324
- "顧客コード" VARCHAR(20) NOT NULL,
325
- "顧客枝番" VARCHAR(10) DEFAULT '00',
326
- "出荷先番号" VARCHAR(10),
327
- "担当者コード" VARCHAR(20),
328
- "希望納期" DATE,
329
- "出荷予定日" DATE,
330
- "受注金額" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
331
- "消費税額" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
332
- "受注合計" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
333
- "ステータス" 受注ステータス DEFAULT '受付済' NOT NULL,
334
- "見積ID" INTEGER,
335
- "顧客注文番号" VARCHAR(50),
336
- "備考" TEXT,
337
- "作成日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
338
- "作成者" VARCHAR(50),
339
- "更新日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
340
- "更新者" VARCHAR(50),
341
- CONSTRAINT "fk_受注データ_顧客"
342
- FOREIGN KEY ("顧客コード", "顧客枝番") REFERENCES "顧客マスタ"("顧客コード", "顧客枝番"),
343
- CONSTRAINT "fk_受注データ_出荷先"
344
- FOREIGN KEY ("顧客コード", "顧客枝番", "出荷先番号") REFERENCES "出荷先マスタ"("取引先コード", "顧客枝番", "出荷先番号"),
345
- CONSTRAINT "fk_受注データ_見積"
346
- FOREIGN KEY ("見積ID") REFERENCES "見積データ"("ID")
347
- );
348
-
349
- -- 受注明細
350
- CREATE TABLE "受注明細" (
351
- "ID" SERIAL PRIMARY KEY,
352
- "受注ID" INTEGER NOT NULL,
353
- "行番号" INTEGER NOT NULL,
354
- "商品コード" VARCHAR(20) NOT NULL,
355
- "商品名" VARCHAR(100) NOT NULL,
356
- "受注数量" DECIMAL(15, 2) NOT NULL,
357
- "引当数量" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
358
- "出荷数量" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
359
- "残数量" DECIMAL(15, 2) NOT NULL,
360
- "単位" VARCHAR(10),
361
- "単価" DECIMAL(15, 2) NOT NULL,
362
- "金額" DECIMAL(15, 2) NOT NULL,
363
- "税区分" 税区分 DEFAULT '外税' NOT NULL,
364
- "消費税率" DECIMAL(5, 2) DEFAULT 10.00 NOT NULL,
365
- "消費税額" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
366
- "倉庫コード" VARCHAR(20),
367
- "希望納期" DATE,
368
- "備考" TEXT,
369
- CONSTRAINT "fk_受注明細_受注"
370
- FOREIGN KEY ("受注ID") REFERENCES "受注データ"("ID") ON DELETE CASCADE,
371
- CONSTRAINT "fk_受注明細_商品"
372
- FOREIGN KEY ("商品コード") REFERENCES "商品マスタ"("商品コード"),
373
- CONSTRAINT "uq_受注明細_行番号" UNIQUE ("受注ID", "行番号")
374
- );
375
-
376
- -- インデックス
377
- CREATE INDEX "idx_見積データ_顧客コード" ON "見積データ"("顧客コード");
378
- CREATE INDEX "idx_見積データ_見積日" ON "見積データ"("見積日");
379
- CREATE INDEX "idx_見積データ_ステータス" ON "見積データ"("ステータス");
380
- CREATE INDEX "idx_受注データ_顧客コード" ON "受注データ"("顧客コード");
381
- CREATE INDEX "idx_受注データ_受注日" ON "受注データ"("受注日");
382
- CREATE INDEX "idx_受注データ_ステータス" ON "受注データ"("ステータス");
383
- CREATE INDEX "idx_受注データ_希望納期" ON "受注データ"("希望納期");
384
- ```
385
-
386
- </details>
387
-
388
- ### 受注ステータス Enum
389
-
390
- <details>
391
- <summary>OrderStatus.java</summary>
392
-
393
- ```java
394
- // src/main/java/com/example/sms/domain/model/sales/OrderStatus.java
395
- package com.example.sms.domain.model.sales;
396
-
397
- import lombok.Getter;
398
- import lombok.RequiredArgsConstructor;
399
-
400
- @Getter
401
- @RequiredArgsConstructor
402
- public enum OrderStatus {
403
- RECEIVED("受付済"),
404
- ALLOCATED("引当済"),
405
- SHIPMENT_INSTRUCTED("出荷指示済"),
406
- SHIPPED("出荷済"),
407
- CANCELLED("キャンセル");
408
-
409
- private final String displayName;
410
-
411
- public static OrderStatus fromDisplayName(String displayName) {
412
- for (OrderStatus status : values()) {
413
- if (status.displayName.equals(displayName)) {
414
- return status;
415
- }
416
- }
417
- throw new IllegalArgumentException("Unknown order status: " + displayName);
418
- }
419
- }
420
- ```
421
-
422
- </details>
423
-
424
- ### 受注エンティティ
425
-
426
- <details>
427
- <summary>SalesOrder.java</summary>
428
-
429
- ```java
430
- // src/main/java/com/example/sms/domain/model/sales/SalesOrder.java
431
- package com.example.sms.domain.model.sales;
432
-
433
- import lombok.AllArgsConstructor;
434
- import lombok.Builder;
435
- import lombok.Data;
436
- import lombok.NoArgsConstructor;
437
-
438
- import java.math.BigDecimal;
439
- import java.time.LocalDate;
440
- import java.time.LocalDateTime;
441
- import java.util.ArrayList;
442
- import java.util.List;
443
-
444
- @Data
445
- @Builder
446
- @NoArgsConstructor
447
- @AllArgsConstructor
448
- @SuppressWarnings("PMD.RedundantFieldInitializer")
449
- public class SalesOrder {
450
- private Integer id;
451
- private String orderNumber;
452
- private LocalDate orderDate;
453
- private String customerCode;
454
- private String customerBranchNumber;
455
- private String shippingDestinationNumber;
456
- private String representativeCode;
457
- private LocalDate requestedDeliveryDate;
458
- private LocalDate scheduledShippingDate;
459
- @Builder.Default
460
- private BigDecimal orderAmount = BigDecimal.ZERO;
461
- @Builder.Default
462
- private BigDecimal taxAmount = BigDecimal.ZERO;
463
- @Builder.Default
464
- private BigDecimal totalAmount = BigDecimal.ZERO;
465
- @Builder.Default
466
- private OrderStatus status = OrderStatus.RECEIVED;
467
- private Integer quotationId;
468
- private String customerOrderNumber;
469
- private String remarks;
470
- private LocalDateTime createdAt;
471
- private String createdBy;
472
- private LocalDateTime updatedAt;
473
- private String updatedBy;
474
-
475
- @Builder.Default
476
- private List<SalesOrderDetail> details = new ArrayList<>();
477
- }
478
- ```
479
-
480
- </details>
481
-
482
- <details>
483
- <summary>SalesOrderDetail.java</summary>
484
-
485
- ```java
486
- // src/main/java/com/example/sms/domain/model/sales/SalesOrderDetail.java
487
- package com.example.sms.domain.model.sales;
488
-
489
- import com.example.sms.domain.model.product.TaxCategory;
490
- import lombok.AllArgsConstructor;
491
- import lombok.Builder;
492
- import lombok.Data;
493
- import lombok.NoArgsConstructor;
494
-
495
- import java.math.BigDecimal;
496
- import java.time.LocalDate;
497
-
498
- @Data
499
- @Builder
500
- @NoArgsConstructor
501
- @AllArgsConstructor
502
- public class SalesOrderDetail {
503
- private Integer id;
504
- private Integer orderId;
505
- private Integer lineNumber;
506
- private String productCode;
507
- private String productName;
508
- private BigDecimal orderQuantity;
509
- private BigDecimal allocatedQuantity;
510
- private BigDecimal shippedQuantity;
511
- private BigDecimal remainingQuantity;
512
- private String unit;
513
- private BigDecimal unitPrice;
514
- private BigDecimal amount;
515
- private TaxCategory taxCategory;
516
- private BigDecimal taxRate;
517
- private BigDecimal taxAmount;
518
- private String warehouseCode;
519
- private LocalDate requestedDeliveryDate;
520
- private String remarks;
521
- }
522
- ```
523
-
524
- </details>
525
-
526
- ### TypeHandler の実装
527
-
528
- 日本語の ENUM 値を Java の Enum に変換するための TypeHandler を実装します。
529
-
530
- <details>
531
- <summary>OrderStatusTypeHandler.java</summary>
532
-
533
- ```java
534
- // src/main/java/com/example/sms/infrastructure/out/persistence/typehandler/OrderStatusTypeHandler.java
535
- package com.example.sms.infrastructure.out.persistence.typehandler;
536
-
537
- import com.example.sms.domain.model.sales.OrderStatus;
538
- import org.apache.ibatis.type.BaseTypeHandler;
539
- import org.apache.ibatis.type.JdbcType;
540
- import org.apache.ibatis.type.MappedTypes;
541
-
542
- import java.sql.*;
543
-
544
- @MappedTypes(OrderStatus.class)
545
- public class OrderStatusTypeHandler extends BaseTypeHandler<OrderStatus> {
546
-
547
- @Override
548
- public void setNonNullParameter(PreparedStatement ps, int i,
549
- OrderStatus parameter, JdbcType jdbcType) throws SQLException {
550
- ps.setObject(i, parameter.getDisplayName(), Types.OTHER);
551
- }
552
-
553
- @Override
554
- public OrderStatus getNullableResult(ResultSet rs, String columnName) throws SQLException {
555
- String value = rs.getString(columnName);
556
- return value == null ? null : OrderStatus.fromDisplayName(value);
557
- }
558
-
559
- @Override
560
- public OrderStatus getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
561
- String value = rs.getString(columnIndex);
562
- return value == null ? null : OrderStatus.fromDisplayName(value);
563
- }
564
-
565
- @Override
566
- public OrderStatus getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
567
- String value = cs.getString(columnIndex);
568
- return value == null ? null : OrderStatus.fromDisplayName(value);
569
- }
570
- }
571
- ```
572
-
573
- </details>
574
-
575
- ### TDD:受注の登録と取得
576
-
577
- #### Red: 失敗するテストを書く
578
-
579
- <details>
580
- <summary>SalesOrderRepositoryTest.java</summary>
581
-
582
- ```java
583
- // src/test/java/com/example/sms/infrastructure/persistence/repository/SalesOrderRepositoryTest.java
584
- package com.example.sms.infrastructure.persistence.repository;
585
-
586
- import com.example.sms.application.port.out.SalesOrderRepository;
587
- import com.example.sms.domain.model.product.TaxCategory;
588
- import com.example.sms.domain.model.sales.*;
589
- import com.example.sms.testsetup.BaseIntegrationTest;
590
- import org.junit.jupiter.api.*;
591
- import org.springframework.beans.factory.annotation.Autowired;
592
-
593
- import java.math.BigDecimal;
594
- import java.time.LocalDate;
595
-
596
- import static org.assertj.core.api.Assertions.*;
597
-
598
- @DisplayName("受注リポジトリ")
599
- class SalesOrderRepositoryTest extends BaseIntegrationTest {
600
-
601
- @Autowired
602
- private SalesOrderRepository salesOrderRepository;
603
-
604
- @BeforeEach
605
- void setUp() {
606
- salesOrderRepository.deleteAll();
607
- }
608
-
609
- @Nested
610
- @DisplayName("受注の登録")
611
- class OrderRegistration {
612
-
613
- @Test
614
- @DisplayName("受注を登録できる")
615
- void canRegisterOrder() {
616
- // Arrange
617
- var order = SalesOrder.builder()
618
- .orderNumber("SO-2025-0001")
619
- .orderDate(LocalDate.of(2025, 1, 20))
620
- .customerCode("CUST-001")
621
- .requestedDeliveryDate(LocalDate.of(2025, 1, 30))
622
- .subtotal(new BigDecimal("50000"))
623
- .taxAmount(new BigDecimal("5000"))
624
- .totalAmount(new BigDecimal("55000"))
625
- .status(OrderStatus.RECEIVED)
626
- .build();
627
-
628
- // Act
629
- salesOrderRepository.save(order);
630
-
631
- // Assert
632
- var result = salesOrderRepository.findByOrderNumber("SO-2025-0001");
633
- assertThat(result).isPresent();
634
- assertThat(result.get().getOrderNumber()).isEqualTo("SO-2025-0001");
635
- assertThat(result.get().getCustomerCode()).isEqualTo("CUST-001");
636
- assertThat(result.get().getTotalAmount()).isEqualByComparingTo(new BigDecimal("55000"));
637
- assertThat(result.get().getStatus()).isEqualTo(OrderStatus.RECEIVED);
638
- }
639
-
640
- @Test
641
- @DisplayName("受注明細を登録できる")
642
- void canRegisterOrderWithDetails() {
643
- // Arrange
644
- var order = SalesOrder.builder()
645
- .orderNumber("SO-2025-0002")
646
- .orderDate(LocalDate.of(2025, 1, 20))
647
- .customerCode("CUST-001")
648
- .subtotal(new BigDecimal("10000"))
649
- .taxAmount(new BigDecimal("1000"))
650
- .totalAmount(new BigDecimal("11000"))
651
- .status(OrderStatus.RECEIVED)
652
- .build();
653
- salesOrderRepository.save(order);
654
-
655
- var detail = SalesOrderDetail.builder()
656
- .orderId(order.getId())
657
- .lineNumber(1)
658
- .productCode("PROD-001")
659
- .productName("テスト商品A")
660
- .orderQuantity(new BigDecimal("10"))
661
- .allocatedQuantity(BigDecimal.ZERO)
662
- .shippedQuantity(BigDecimal.ZERO)
663
- .remainingQuantity(new BigDecimal("10"))
664
- .unit("個")
665
- .unitPrice(new BigDecimal("1000"))
666
- .amount(new BigDecimal("10000"))
667
- .taxCategory(TaxCategory.EXCLUSIVE)
668
- .taxRate(new BigDecimal("10.00"))
669
- .taxAmount(new BigDecimal("1000"))
670
- .warehouseCode("WH-001")
671
- .build();
672
-
673
- // Act
674
- salesOrderRepository.saveDetail(detail);
675
-
676
- // Assert
677
- var result = salesOrderRepository.findByIdWithDetails(order.getId());
678
- assertThat(result).isPresent();
679
- assertThat(result.get().getDetails()).hasSize(1);
680
- assertThat(result.get().getDetails().get(0).getProductCode()).isEqualTo("PROD-001");
681
- assertThat(result.get().getDetails().get(0).getOrderQuantity())
682
- .isEqualByComparingTo(new BigDecimal("10"));
683
- }
684
-
685
- @Test
686
- @DisplayName("受注明細の数量を更新できる")
687
- void canUpdateDetailQuantities() {
688
- // Arrange
689
- var order = SalesOrder.builder()
690
- .orderNumber("SO-2025-0003")
691
- .orderDate(LocalDate.of(2025, 1, 20))
692
- .customerCode("CUST-001")
693
- .subtotal(new BigDecimal("10000"))
694
- .taxAmount(new BigDecimal("1000"))
695
- .totalAmount(new BigDecimal("11000"))
696
- .status(OrderStatus.RECEIVED)
697
- .build();
698
- salesOrderRepository.save(order);
699
-
700
- var detail = SalesOrderDetail.builder()
701
- .orderId(order.getId())
702
- .lineNumber(1)
703
- .productCode("PROD-001")
704
- .productName("テスト商品A")
705
- .orderQuantity(new BigDecimal("10"))
706
- .allocatedQuantity(BigDecimal.ZERO)
707
- .shippedQuantity(BigDecimal.ZERO)
708
- .remainingQuantity(new BigDecimal("10"))
709
- .unit("個")
710
- .unitPrice(new BigDecimal("1000"))
711
- .amount(new BigDecimal("10000"))
712
- .taxCategory(TaxCategory.EXCLUSIVE)
713
- .taxRate(new BigDecimal("10.00"))
714
- .taxAmount(new BigDecimal("1000"))
715
- .build();
716
- salesOrderRepository.saveDetail(detail);
717
-
718
- // Act: 5個引当
719
- salesOrderRepository.updateDetailQuantities(
720
- detail.getId(),
721
- new BigDecimal("5"), // 引当数量
722
- BigDecimal.ZERO, // 出荷数量
723
- new BigDecimal("5") // 残数量
724
- );
725
-
726
- // Assert
727
- var result = salesOrderRepository.findByIdWithDetails(order.getId());
728
- assertThat(result).isPresent();
729
- var updatedDetail = result.get().getDetails().get(0);
730
- assertThat(updatedDetail.getAllocatedQuantity()).isEqualByComparingTo(new BigDecimal("5"));
731
- assertThat(updatedDetail.getRemainingQuantity()).isEqualByComparingTo(new BigDecimal("5"));
732
- }
733
- }
734
-
735
- @Nested
736
- @DisplayName("受注の検索")
737
- class OrderSearch {
738
-
739
- @Test
740
- @DisplayName("納期範囲で受注を検索できる")
741
- void canSearchByDeliveryDateRange() {
742
- // Arrange
743
- var order1 = SalesOrder.builder()
744
- .orderNumber("SO-2025-0004")
745
- .orderDate(LocalDate.of(2025, 1, 15))
746
- .customerCode("CUST-001")
747
- .requestedDeliveryDate(LocalDate.of(2025, 1, 25))
748
- .subtotal(BigDecimal.ZERO)
749
- .taxAmount(BigDecimal.ZERO)
750
- .totalAmount(BigDecimal.ZERO)
751
- .status(OrderStatus.RECEIVED)
752
- .build();
753
- salesOrderRepository.save(order1);
754
-
755
- var order2 = SalesOrder.builder()
756
- .orderNumber("SO-2025-0005")
757
- .orderDate(LocalDate.of(2025, 1, 20))
758
- .customerCode("CUST-001")
759
- .requestedDeliveryDate(LocalDate.of(2025, 2, 15))
760
- .subtotal(BigDecimal.ZERO)
761
- .taxAmount(BigDecimal.ZERO)
762
- .totalAmount(BigDecimal.ZERO)
763
- .status(OrderStatus.RECEIVED)
764
- .build();
765
- salesOrderRepository.save(order2);
766
-
767
- // Act: 1月中の納期で検索
768
- var januaryOrders = salesOrderRepository.findByDeliveryDateRange(
769
- LocalDate.of(2025, 1, 1),
770
- LocalDate.of(2025, 1, 31)
771
- );
772
-
773
- // Assert
774
- assertThat(januaryOrders).hasSize(1);
775
- assertThat(januaryOrders.get(0).getOrderNumber()).isEqualTo("SO-2025-0004");
776
- }
777
- }
778
- }
779
- ```
780
-
781
- </details>
782
-
783
- #### Green: テストを通す実装
784
-
785
- <details>
786
- <summary>SalesOrderRepository.java</summary>
787
-
788
- ```java
789
- // src/main/java/com/example/sms/application/port/out/SalesOrderRepository.java
790
- package com.example.sms.application.port.out;
791
-
792
- import com.example.sms.domain.model.sales.OrderStatus;
793
- import com.example.sms.domain.model.sales.SalesOrder;
794
- import com.example.sms.domain.model.sales.SalesOrderDetail;
795
-
796
- import java.math.BigDecimal;
797
- import java.time.LocalDate;
798
- import java.util.List;
799
- import java.util.Optional;
800
-
801
- public interface SalesOrderRepository {
802
-
803
- void save(SalesOrder order);
804
-
805
- void saveDetail(SalesOrderDetail detail);
806
-
807
- Optional<SalesOrder> findById(Integer id);
808
-
809
- Optional<SalesOrder> findByOrderNumber(String orderNumber);
810
-
811
- Optional<SalesOrder> findByIdWithDetails(Integer id);
812
-
813
- List<SalesOrder> findByDeliveryDateRange(LocalDate from, LocalDate to);
814
-
815
- void updateStatus(Integer id, OrderStatus status);
816
-
817
- void updateDetailQuantities(Integer detailId,
818
- BigDecimal allocatedQuantity,
819
- BigDecimal shippedQuantity,
820
- BigDecimal remainingQuantity);
821
-
822
- void deleteAll();
823
- }
824
- ```
825
-
826
- </details>
827
-
828
- <details>
829
- <summary>SalesOrderMapper.xml</summary>
830
-
831
- ```xml
832
- <?xml version="1.0" encoding="UTF-8" ?>
833
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
834
- "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
835
-
836
- <!-- src/main/resources/mapper/SalesOrderMapper.xml -->
837
- <mapper namespace="com.example.sms.infrastructure.persistence.mapper.SalesOrderMapper">
838
-
839
- <resultMap id="SalesOrderResultMap" type="com.example.sms.domain.model.sales.SalesOrder">
840
- <id property="id" column="ID"/>
841
- <result property="orderNumber" column="受注番号"/>
842
- <result property="orderDate" column="受注日"/>
843
- <result property="customerCode" column="顧客コード"/>
844
- <result property="customerBranchNumber" column="顧客枝番"/>
845
- <result property="shippingDestinationNumber" column="出荷先番号"/>
846
- <result property="representativeCode" column="担当者コード"/>
847
- <result property="requestedDeliveryDate" column="希望納期"/>
848
- <result property="scheduledShippingDate" column="出荷予定日"/>
849
- <result property="orderAmount" column="受注金額"/>
850
- <result property="taxAmount" column="消費税額"/>
851
- <result property="totalAmount" column="受注合計"/>
852
- <result property="status" column="ステータス"
853
- typeHandler="com.example.sms.infrastructure.out.persistence.typehandler.OrderStatusTypeHandler"/>
854
- <result property="quotationId" column="見積ID"/>
855
- <result property="customerOrderNumber" column="顧客注文番号"/>
856
- <result property="remarks" column="備考"/>
857
- <result property="createdAt" column="作成日時"/>
858
- <result property="createdBy" column="作成者"/>
859
- <result property="updatedAt" column="更新日時"/>
860
- <result property="updatedBy" column="更新者"/>
861
- <collection property="details" ofType="com.example.sms.domain.model.sales.SalesOrderDetail">
862
- <id property="id" column="明細ID"/>
863
- <result property="orderId" column="受注ID"/>
864
- <result property="lineNumber" column="行番号"/>
865
- <result property="productCode" column="商品コード"/>
866
- <result property="productName" column="商品名"/>
867
- <result property="orderQuantity" column="受注数量"/>
868
- <result property="allocatedQuantity" column="引当数量"/>
869
- <result property="shippedQuantity" column="出荷数量"/>
870
- <result property="remainingQuantity" column="残数量"/>
871
- <result property="unit" column="単位"/>
872
- <result property="unitPrice" column="単価"/>
873
- <result property="amount" column="金額"/>
874
- <result property="taxCategory" column="税区分"
875
- typeHandler="com.example.sms.infrastructure.out.persistence.typehandler.TaxCategoryTypeHandler"/>
876
- <result property="taxRate" column="消費税率"/>
877
- <result property="taxAmount" column="明細消費税額"/>
878
- <result property="warehouseCode" column="倉庫コード"/>
879
- <result property="requestedDeliveryDate" column="明細希望納期"/>
880
- </collection>
881
- </resultMap>
882
-
883
- <insert id="insertHeader" parameterType="com.example.sms.domain.model.sales.SalesOrder"
884
- useGeneratedKeys="true" keyProperty="id" keyColumn="ID">
885
- INSERT INTO "受注データ" (
886
- "受注番号", "受注日", "顧客コード", "顧客枝番", "出荷先番号",
887
- "担当者コード", "希望納期", "出荷予定日", "受注金額", "消費税額",
888
- "受注合計", "ステータス", "見積ID", "顧客注文番号", "備考",
889
- "作成日時", "作成者", "更新日時", "更新者"
890
- ) VALUES (
891
- #{orderNumber}, #{orderDate}, #{customerCode}, #{customerBranchNumber}, #{shippingDestinationNumber},
892
- #{representativeCode}, #{requestedDeliveryDate}, #{scheduledShippingDate}, #{orderAmount}, #{taxAmount},
893
- #{totalAmount},
894
- #{status, typeHandler=com.example.sms.infrastructure.out.persistence.typehandler.OrderStatusTypeHandler}::受注ステータス,
895
- #{quotationId}, #{customerOrderNumber}, #{remarks},
896
- CURRENT_TIMESTAMP, #{createdBy}, CURRENT_TIMESTAMP, #{updatedBy}
897
- )
898
- </insert>
899
-
900
- <insert id="insertDetail" useGeneratedKeys="true" keyProperty="id" keyColumn="ID">
901
- INSERT INTO "受注明細" (
902
- "受注ID", "行番号", "商品コード", "商品名", "受注数量",
903
- "引当数量", "出荷数量", "残数量", "単位", "単価", "金額",
904
- "税区分", "消費税率", "消費税額", "倉庫コード", "希望納期"
905
- ) VALUES (
906
- #{orderId}, #{lineNumber}, #{productCode}, #{productName}, #{orderQuantity},
907
- #{allocatedQuantity}, #{shippedQuantity}, #{remainingQuantity}, #{unit},
908
- #{unitPrice}, #{amount},
909
- #{taxCategory, typeHandler=com.example.sms.infrastructure.out.persistence.typehandler.TaxCategoryTypeHandler},
910
- #{taxRate}, #{taxAmount}, #{warehouseCode}, #{requestedDeliveryDate}
911
- )
912
- </insert>
913
-
914
- <select id="findByOrderNumber" resultMap="SalesOrderResultMap">
915
- SELECT * FROM "受注データ" WHERE "受注番号" = #{orderNumber}
916
- </select>
917
-
918
- <select id="findDetailsByOrderId" resultMap="SalesOrderDetailResultMap">
919
- SELECT * FROM "受注明細"
920
- WHERE "受注ID" = #{orderId}
921
- ORDER BY "行番号"
922
- </select>
923
-
924
- <select id="findByDeliveryDateRange" resultMap="SalesOrderResultMap">
925
- SELECT * FROM "受注データ"
926
- WHERE "希望納期" BETWEEN #{from} AND #{to}
927
- ORDER BY "希望納期"
928
- </select>
929
-
930
- <update id="updateStatus">
931
- UPDATE "受注データ"
932
- SET "ステータス" = #{status, typeHandler=com.example.sms.infrastructure.out.persistence.typehandler.OrderStatusTypeHandler},
933
- "更新日時" = CURRENT_TIMESTAMP
934
- WHERE "ID" = #{id}
935
- </update>
936
-
937
- <update id="updateDetailQuantities">
938
- UPDATE "受注明細"
939
- SET "引当数量" = #{allocatedQuantity},
940
- "出荷数量" = #{shippedQuantity},
941
- "残数量" = #{remainingQuantity}
942
- WHERE "ID" = #{detailId}
943
- </update>
944
-
945
- <delete id="deleteAll">
946
- DELETE FROM "受注明細";
947
- DELETE FROM "受注データ";
948
- </delete>
949
-
950
- </mapper>
951
- ```
952
-
953
- </details>
954
-
955
- ---
956
-
957
- ## 6.2 出荷業務の DB 設計
958
-
959
- ### 出荷業務の流れ
960
-
961
- 出荷業務は、受注データを起点として商品を顧客に届けるまでのプロセスです。
962
-
963
- ```plantuml
964
- @startuml
965
-
966
- title 出荷業務フロー
967
-
968
- |倉庫部門|
969
- start
970
- :受注データ確認;
971
- :出荷指示作成;
972
-
973
- :ピッキングリスト発行;
974
-
975
- :ピッキング作業;
976
- note right
977
- 倉庫から商品を
978
- ピックアップ
979
- end note
980
-
981
- :検品・梱包;
982
-
983
- :出荷;
984
- note right
985
- 配送業者に引渡し
986
- 追跡番号取得
987
- end note
988
-
989
- |営業部門|
990
- :売上計上;
991
- :納品書発行;
992
-
993
- stop
994
-
995
- @enduml
996
- ```
997
-
998
- ### 出荷指示データ・出荷明細データ
999
-
1000
- #### 出荷関連テーブルの ER 図
1001
-
1002
- ```plantuml
1003
- @startuml
1004
-
1005
- title 出荷関連テーブル
1006
-
1007
- entity 受注データ {
1008
- ID <<PK>>
1009
- --
1010
- 受注番号
1011
- 受注日
1012
- 顧客コード
1013
- ステータス
1014
- ...
1015
- }
1016
-
1017
- entity 受注明細 {
1018
- ID <<PK>>
1019
- --
1020
- 受注ID <<FK>>
1021
- 商品コード
1022
- 受注数量
1023
- 出荷数量
1024
- 残数量
1025
- ...
1026
- }
1027
-
1028
- entity 出荷データ {
1029
- ID <<PK>>
1030
- --
1031
- 出荷番号 <<UK>>
1032
- 出荷日
1033
- 受注ID <<FK>>
1034
- 顧客コード <<FK>>
1035
- 顧客枝番 <<FK>>
1036
- 出荷先番号 <<FK>>
1037
- 出荷先名
1038
- 出荷先郵便番号
1039
- 出荷先住所1
1040
- 出荷先住所2
1041
- 担当者コード
1042
- 倉庫コード
1043
- ステータス
1044
- 備考
1045
- 作成日時
1046
- 更新日時
1047
- }
1048
-
1049
- entity 出荷明細 {
1050
- ID <<PK>>
1051
- --
1052
- 出荷ID <<FK>>
1053
- 行番号
1054
- 受注明細ID <<FK>>
1055
- 商品コード <<FK>>
1056
- 商品名
1057
- 出荷数量
1058
- 単位
1059
- 単価
1060
- 金額
1061
- 税区分
1062
- 消費税率
1063
- 消費税額
1064
- 倉庫コード
1065
- 備考
1066
- }
1067
-
1068
- 受注データ ||--o{ 受注明細
1069
- 受注データ ||--o{ 出荷データ
1070
- 出荷データ ||--o{ 出荷明細
1071
- 受注明細 ||--o{ 出荷明細
1072
-
1073
- @enduml
1074
- ```
1075
-
1076
- ### 出荷ステータスの定義
1077
-
1078
- ```plantuml
1079
- @startuml
1080
-
1081
- title 出荷ステータス遷移図
1082
-
1083
- [*] --> 出荷指示済
1084
-
1085
- 出荷指示済 --> 出荷準備中 : 出荷準備開始
1086
- 出荷準備中 --> 出荷済 : 出荷完了
1087
-
1088
- 出荷済 --> [*]
1089
-
1090
- 出荷指示済 --> キャンセル
1091
- 出荷準備中 --> キャンセル
1092
-
1093
- キャンセル --> [*]
1094
-
1095
- @enduml
1096
- ```
1097
-
1098
- | ステータス | 説明 |
1099
- |-----------|------|
1100
- | **出荷指示済** | 出荷指示が作成された状態 |
1101
- | **出荷準備中** | 出荷準備作業中の状態 |
1102
- | **出荷済** | 配送業者に引き渡した状態 |
1103
- | **キャンセル** | 出荷指示がキャンセルされた状態 |
1104
-
1105
- ### マイグレーション:出荷関連テーブルの作成
1106
-
1107
- <details>
1108
- <summary>V008__create_shipment_tables.sql</summary>
1109
-
1110
- ```sql
1111
- -- src/main/resources/db/migration/V008__create_shipment_tables.sql
1112
-
1113
- -- 出荷ステータス
1114
- CREATE TYPE 出荷ステータス AS ENUM ('出荷指示済', '出荷準備中', '出荷済', 'キャンセル');
1115
-
1116
- -- 出荷データ(ヘッダ)
1117
- CREATE TABLE "出荷データ" (
1118
- "ID" SERIAL PRIMARY KEY,
1119
- "出荷番号" VARCHAR(20) UNIQUE NOT NULL,
1120
- "出荷日" DATE NOT NULL,
1121
- "受注ID" INTEGER NOT NULL,
1122
- "顧客コード" VARCHAR(20) NOT NULL,
1123
- "顧客枝番" VARCHAR(10) DEFAULT '00',
1124
- "出荷先番号" VARCHAR(10),
1125
- "出荷先名" VARCHAR(100),
1126
- "出荷先郵便番号" VARCHAR(10),
1127
- "出荷先住所1" VARCHAR(100),
1128
- "出荷先住所2" VARCHAR(100),
1129
- "担当者コード" VARCHAR(20),
1130
- "倉庫コード" VARCHAR(20),
1131
- "ステータス" 出荷ステータス DEFAULT '出荷指示済' NOT NULL,
1132
- "備考" TEXT,
1133
- "作成日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
1134
- "作成者" VARCHAR(50),
1135
- "更新日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
1136
- "更新者" VARCHAR(50),
1137
- CONSTRAINT "fk_出荷データ_受注"
1138
- FOREIGN KEY ("受注ID") REFERENCES "受注データ"("ID"),
1139
- CONSTRAINT "fk_出荷データ_顧客"
1140
- FOREIGN KEY ("顧客コード", "顧客枝番") REFERENCES "顧客マスタ"("顧客コード", "顧客枝番"),
1141
- CONSTRAINT "fk_出荷データ_出荷先"
1142
- FOREIGN KEY ("顧客コード", "顧客枝番", "出荷先番号") REFERENCES "出荷先マスタ"("取引先コード", "顧客枝番", "出荷先番号")
1143
- );
1144
-
1145
- -- 出荷明細
1146
- CREATE TABLE "出荷明細" (
1147
- "ID" SERIAL PRIMARY KEY,
1148
- "出荷ID" INTEGER NOT NULL,
1149
- "行番号" INTEGER NOT NULL,
1150
- "受注明細ID" INTEGER NOT NULL,
1151
- "商品コード" VARCHAR(20) NOT NULL,
1152
- "商品名" VARCHAR(100) NOT NULL,
1153
- "出荷数量" DECIMAL(15, 2) NOT NULL,
1154
- "単位" VARCHAR(10),
1155
- "単価" DECIMAL(15, 2) NOT NULL,
1156
- "金額" DECIMAL(15, 2) NOT NULL,
1157
- "税区分" 税区分 DEFAULT '外税' NOT NULL,
1158
- "消費税率" DECIMAL(5, 2) DEFAULT 10.00 NOT NULL,
1159
- "消費税額" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
1160
- "倉庫コード" VARCHAR(20),
1161
- "備考" TEXT,
1162
- CONSTRAINT "fk_出荷明細_出荷"
1163
- FOREIGN KEY ("出荷ID") REFERENCES "出荷データ"("ID") ON DELETE CASCADE,
1164
- CONSTRAINT "fk_出荷明細_受注明細"
1165
- FOREIGN KEY ("受注明細ID") REFERENCES "受注明細"("ID"),
1166
- CONSTRAINT "fk_出荷明細_商品"
1167
- FOREIGN KEY ("商品コード") REFERENCES "商品マスタ"("商品コード"),
1168
- CONSTRAINT "uq_出荷明細_行番号" UNIQUE ("出荷ID", "行番号")
1169
- );
1170
-
1171
- -- インデックス
1172
- CREATE INDEX "idx_出荷データ_受注ID" ON "出荷データ"("受注ID");
1173
- CREATE INDEX "idx_出荷データ_顧客コード" ON "出荷データ"("顧客コード");
1174
- CREATE INDEX "idx_出荷データ_出荷日" ON "出荷データ"("出荷日");
1175
- CREATE INDEX "idx_出荷データ_ステータス" ON "出荷データ"("ステータス");
1176
- ```
1177
-
1178
- </details>
1179
-
1180
- ### 出荷ステータス Enum
1181
-
1182
- <details>
1183
- <summary>ShipmentStatus.java</summary>
1184
-
1185
- ```java
1186
- // src/main/java/com/example/sms/domain/model/shipping/ShipmentStatus.java
1187
- package com.example.sms.domain.model.shipping;
1188
-
1189
- import lombok.Getter;
1190
- import lombok.RequiredArgsConstructor;
1191
-
1192
- @Getter
1193
- @RequiredArgsConstructor
1194
- public enum ShipmentStatus {
1195
- INSTRUCTED("出荷指示済"),
1196
- PREPARING("出荷準備中"),
1197
- SHIPPED("出荷済"),
1198
- CANCELLED("キャンセル");
1199
-
1200
- private final String displayName;
1201
-
1202
- public static ShipmentStatus fromDisplayName(String displayName) {
1203
- for (ShipmentStatus status : values()) {
1204
- if (status.displayName.equals(displayName)) {
1205
- return status;
1206
- }
1207
- }
1208
- throw new IllegalArgumentException("Unknown shipment status: " + displayName);
1209
- }
1210
- }
1211
- ```
1212
-
1213
- </details>
1214
-
1215
- ### 出荷エンティティ
1216
-
1217
- <details>
1218
- <summary>Shipment.java</summary>
1219
-
1220
- ```java
1221
- // src/main/java/com/example/sms/domain/model/shipping/Shipment.java
1222
- package com.example.sms.domain.model.shipping;
1223
-
1224
- import lombok.AllArgsConstructor;
1225
- import lombok.Builder;
1226
- import lombok.Data;
1227
- import lombok.NoArgsConstructor;
1228
-
1229
- import java.time.LocalDate;
1230
- import java.time.LocalDateTime;
1231
- import java.util.List;
1232
-
1233
- @Data
1234
- @Builder
1235
- @NoArgsConstructor
1236
- @AllArgsConstructor
1237
- @SuppressWarnings("PMD.RedundantFieldInitializer")
1238
- public class Shipment {
1239
- private Integer id;
1240
- private String shipmentNumber;
1241
- private LocalDate shipmentDate;
1242
- private Integer orderId;
1243
- private String customerCode;
1244
- private String customerBranchNumber;
1245
- private String shippingDestinationNumber;
1246
- private String shippingDestinationName;
1247
- private String shippingDestinationPostalCode;
1248
- private String shippingDestinationAddress1;
1249
- private String shippingDestinationAddress2;
1250
- private String representativeCode;
1251
- private String warehouseCode;
1252
- @Builder.Default
1253
- private ShipmentStatus status = ShipmentStatus.INSTRUCTED;
1254
- private String remarks;
1255
- private LocalDateTime createdAt;
1256
- private String createdBy;
1257
- private LocalDateTime updatedAt;
1258
- private String updatedBy;
1259
- private List<ShipmentDetail> details;
1260
- }
1261
- ```
1262
-
1263
- </details>
1264
-
1265
- <details>
1266
- <summary>ShipmentDetail.java</summary>
1267
-
1268
- ```java
1269
- // src/main/java/com/example/sms/domain/model/shipping/ShipmentDetail.java
1270
- package com.example.sms.domain.model.shipping;
1271
-
1272
- import com.example.sms.domain.model.product.TaxCategory;
1273
- import lombok.AllArgsConstructor;
1274
- import lombok.Builder;
1275
- import lombok.Data;
1276
- import lombok.NoArgsConstructor;
1277
-
1278
- import java.math.BigDecimal;
1279
-
1280
- @Data
1281
- @Builder
1282
- @NoArgsConstructor
1283
- @AllArgsConstructor
1284
- public class ShipmentDetail {
1285
- private Integer id;
1286
- private Integer shipmentId;
1287
- private Integer lineNumber;
1288
- private Integer orderDetailId;
1289
- private String productCode;
1290
- private String productName;
1291
- private BigDecimal shippedQuantity;
1292
- private String unit;
1293
- private BigDecimal unitPrice;
1294
- private BigDecimal amount;
1295
- private TaxCategory taxCategory;
1296
- private BigDecimal taxRate;
1297
- private BigDecimal taxAmount;
1298
- private String warehouseCode;
1299
- private String remarks;
1300
- }
1301
- ```
1302
-
1303
- </details>
1304
-
1305
- ### TDD:出荷指示の登録と取得
1306
-
1307
- <details>
1308
- <summary>ShipmentInstructionRepositoryTest.java</summary>
1309
-
1310
- ```java
1311
- // src/test/java/com/example/sms/infrastructure/persistence/repository/ShipmentInstructionRepositoryTest.java
1312
- package com.example.sms.infrastructure.persistence.repository;
1313
-
1314
- import com.example.sms.application.port.out.SalesOrderRepository;
1315
- import com.example.sms.application.port.out.ShipmentInstructionRepository;
1316
- import com.example.sms.domain.model.sales.*;
1317
- import com.example.sms.testsetup.BaseIntegrationTest;
1318
- import org.junit.jupiter.api.*;
1319
- import org.springframework.beans.factory.annotation.Autowired;
1320
-
1321
- import java.math.BigDecimal;
1322
- import java.time.LocalDate;
1323
-
1324
- import static org.assertj.core.api.Assertions.*;
1325
-
1326
- @DisplayName("出荷指示リポジトリ")
1327
- class ShipmentInstructionRepositoryTest extends BaseIntegrationTest {
1328
-
1329
- @Autowired
1330
- private ShipmentInstructionRepository shipmentInstructionRepository;
1331
-
1332
- @Autowired
1333
- private SalesOrderRepository salesOrderRepository;
1334
-
1335
- @BeforeEach
1336
- void setUp() {
1337
- shipmentInstructionRepository.deleteAll();
1338
- salesOrderRepository.deleteAll();
1339
- setupOrderData();
1340
- }
1341
-
1342
- private void setupOrderData() {
1343
- // 受注データ準備
1344
- var order = SalesOrder.builder()
1345
- .orderNumber("SO-2025-0001")
1346
- .orderDate(LocalDate.of(2025, 1, 20))
1347
- .customerCode("CUST-001")
1348
- .requestedDeliveryDate(LocalDate.of(2025, 1, 30))
1349
- .subtotal(new BigDecimal("50000"))
1350
- .taxAmount(new BigDecimal("5000"))
1351
- .totalAmount(new BigDecimal("55000"))
1352
- .status(OrderStatus.RECEIVED)
1353
- .build();
1354
- salesOrderRepository.save(order);
1355
- }
1356
-
1357
- @Nested
1358
- @DisplayName("出荷指示の登録")
1359
- class ShipmentInstructionRegistration {
1360
-
1361
- @Test
1362
- @DisplayName("出荷指示を登録できる")
1363
- void canRegisterShipmentInstruction() {
1364
- // Arrange
1365
- var order = salesOrderRepository.findByOrderNumber("SO-2025-0001").get();
1366
- var instruction = ShipmentInstruction.builder()
1367
- .instructionNumber("SI-2025-0001")
1368
- .instructionDate(LocalDate.of(2025, 1, 25))
1369
- .orderId(order.getId())
1370
- .customerCode("CUST-001")
1371
- .scheduledShipDate(LocalDate.of(2025, 1, 28))
1372
- .warehouseCode("WH-001")
1373
- .status(ShipmentStatus.INSTRUCTED)
1374
- .build();
1375
-
1376
- // Act
1377
- shipmentInstructionRepository.save(instruction);
1378
-
1379
- // Assert
1380
- var result = shipmentInstructionRepository.findByInstructionNumber("SI-2025-0001");
1381
- assertThat(result).isPresent();
1382
- assertThat(result.get().getOrderId()).isEqualTo(order.getId());
1383
- assertThat(result.get().getStatus()).isEqualTo(ShipmentStatus.INSTRUCTED);
1384
- }
1385
-
1386
- @Test
1387
- @DisplayName("出荷指示ステータスを更新できる")
1388
- void canUpdateShipmentStatus() {
1389
- // Arrange
1390
- var order = salesOrderRepository.findByOrderNumber("SO-2025-0001").get();
1391
- var instruction = ShipmentInstruction.builder()
1392
- .instructionNumber("SI-2025-0002")
1393
- .instructionDate(LocalDate.of(2025, 1, 25))
1394
- .orderId(order.getId())
1395
- .customerCode("CUST-001")
1396
- .scheduledShipDate(LocalDate.of(2025, 1, 28))
1397
- .warehouseCode("WH-001")
1398
- .status(ShipmentStatus.INSTRUCTED)
1399
- .build();
1400
- shipmentInstructionRepository.save(instruction);
1401
-
1402
- // Act: ピッキング開始
1403
- shipmentInstructionRepository.updateStatus(instruction.getId(), ShipmentStatus.PICKING);
1404
-
1405
- // Assert
1406
- var result = shipmentInstructionRepository.findById(instruction.getId());
1407
- assertThat(result).isPresent();
1408
- assertThat(result.get().getStatus()).isEqualTo(ShipmentStatus.PICKING);
1409
- }
1410
-
1411
- @Test
1412
- @DisplayName("追跡番号を登録できる")
1413
- void canRegisterTrackingNumber() {
1414
- // Arrange
1415
- var order = salesOrderRepository.findByOrderNumber("SO-2025-0001").get();
1416
- var instruction = ShipmentInstruction.builder()
1417
- .instructionNumber("SI-2025-0003")
1418
- .instructionDate(LocalDate.of(2025, 1, 25))
1419
- .orderId(order.getId())
1420
- .customerCode("CUST-001")
1421
- .scheduledShipDate(LocalDate.of(2025, 1, 28))
1422
- .warehouseCode("WH-001")
1423
- .status(ShipmentStatus.SHIPPED)
1424
- .carrierCode("YAMATO")
1425
- .trackingNumber("1234-5678-9012")
1426
- .build();
1427
-
1428
- // Act
1429
- shipmentInstructionRepository.save(instruction);
1430
-
1431
- // Assert
1432
- var result = shipmentInstructionRepository.findByInstructionNumber("SI-2025-0003");
1433
- assertThat(result).isPresent();
1434
- assertThat(result.get().getCarrierCode()).isEqualTo("YAMATO");
1435
- assertThat(result.get().getTrackingNumber()).isEqualTo("1234-5678-9012");
1436
- }
1437
- }
1438
- }
1439
- ```
1440
-
1441
- </details>
1442
-
1443
- ### 受注から出荷指示を作成するサービス
1444
-
1445
- <details>
1446
- <summary>ShipmentService.java</summary>
1447
-
1448
- ```java
1449
- // src/main/java/com/example/sms/application/service/ShipmentService.java
1450
- package com.example.sms.application.service;
1451
-
1452
- import com.example.sms.application.port.out.*;
1453
- import com.example.sms.domain.model.sales.*;
1454
- import lombok.RequiredArgsConstructor;
1455
- import org.springframework.stereotype.Service;
1456
- import org.springframework.transaction.annotation.Transactional;
1457
-
1458
- import java.math.BigDecimal;
1459
- import java.time.LocalDate;
1460
-
1461
- @Service
1462
- @RequiredArgsConstructor
1463
- public class ShipmentService {
1464
-
1465
- private final SalesOrderRepository salesOrderRepository;
1466
- private final ShipmentInstructionRepository shipmentInstructionRepository;
1467
-
1468
- /**
1469
- * 受注から出荷指示を作成する
1470
- */
1471
- @Transactional
1472
- public ShipmentInstruction createShipmentInstruction(Integer orderId,
1473
- LocalDate scheduledShipDate,
1474
- String warehouseCode) {
1475
- var order = salesOrderRepository.findByIdWithDetails(orderId)
1476
- .orElseThrow(() -> new IllegalArgumentException("Order not found: " + orderId));
1477
-
1478
- if (order.getStatus() != OrderStatus.RECEIVED && order.getStatus() != OrderStatus.ALLOCATED) {
1479
- throw new IllegalStateException("Cannot create shipment instruction for order with status: "
1480
- + order.getStatus());
1481
- }
1482
-
1483
- // 出荷指示ヘッダ作成
1484
- var instruction = ShipmentInstruction.builder()
1485
- .instructionNumber(generateInstructionNumber(LocalDate.now()))
1486
- .instructionDate(LocalDate.now())
1487
- .orderId(orderId)
1488
- .customerCode(order.getCustomerCode())
1489
- .shipToCode(order.getShipToCode())
1490
- .scheduledShipDate(scheduledShipDate)
1491
- .warehouseCode(warehouseCode)
1492
- .status(ShipmentStatus.INSTRUCTED)
1493
- .build();
1494
- shipmentInstructionRepository.save(instruction);
1495
-
1496
- // 出荷指示明細作成
1497
- int lineNumber = 1;
1498
- for (var orderDetail : order.getDetails()) {
1499
- if (orderDetail.getRemainingQuantity().compareTo(BigDecimal.ZERO) > 0) {
1500
- var instructionDetail = ShipmentInstructionDetail.builder()
1501
- .shipmentInstructionId(instruction.getId())
1502
- .lineNumber(lineNumber++)
1503
- .orderDetailId(orderDetail.getId())
1504
- .productCode(orderDetail.getProductCode())
1505
- .productName(orderDetail.getProductName())
1506
- .instructedQuantity(orderDetail.getRemainingQuantity())
1507
- .shippedQuantity(BigDecimal.ZERO)
1508
- .unit(orderDetail.getUnit())
1509
- .build();
1510
- shipmentInstructionRepository.saveDetail(instructionDetail);
1511
- }
1512
- }
1513
-
1514
- // 受注ステータスを更新
1515
- salesOrderRepository.updateStatus(orderId, OrderStatus.SHIPMENT_INSTRUCTED);
1516
-
1517
- return instruction;
1518
- }
1519
-
1520
- private String generateInstructionNumber(LocalDate date) {
1521
- return String.format("SI-%d-%04d", date.getYear(), System.currentTimeMillis() % 10000);
1522
- }
1523
- }
1524
- ```
1525
-
1526
- </details>
1527
-
1528
- ---
1529
-
1530
- ## 6.3 売上業務の DB 設計
1531
-
1532
- ### 売上データ・売上明細データの構造
1533
-
1534
- #### 売上関連テーブルの ER 図
1535
-
1536
- ```plantuml
1537
- @startuml
1538
-
1539
- title 売上関連テーブル
1540
-
1541
- entity 出荷データ {
1542
- ID <<PK>>
1543
- --
1544
- 出荷番号
1545
- 受注ID <<FK>>
1546
- ステータス
1547
- ...
1548
- }
1549
-
1550
- entity 売上データ {
1551
- ID <<PK>>
1552
- --
1553
- 売上番号 <<UK>>
1554
- 売上日
1555
- 受注ID <<FK>>
1556
- 出荷ID <<FK>>
1557
- 顧客コード <<FK>>
1558
- 顧客枝番 <<FK>>
1559
- 担当者コード
1560
- 売上金額
1561
- 消費税額
1562
- 売上合計
1563
- ステータス
1564
- 請求ID
1565
- 備考
1566
- 作成日時
1567
- 更新日時
1568
- }
1569
-
1570
- entity 売上明細 {
1571
- ID <<PK>>
1572
- --
1573
- 売上ID <<FK>>
1574
- 行番号
1575
- 受注明細ID <<FK>>
1576
- 出荷明細ID <<FK>>
1577
- 商品コード <<FK>>
1578
- 商品名
1579
- 売上数量
1580
- 単位
1581
- 単価
1582
- 金額
1583
- 税区分
1584
- 消費税率
1585
- 消費税額
1586
- 備考
1587
- }
1588
-
1589
- entity 返品データ {
1590
- ID <<PK>>
1591
- --
1592
- 返品番号 <<UK>>
1593
- 返品日
1594
- 売上ID <<FK>>
1595
- 顧客コード <<FK>>
1596
- 返品理由
1597
- 返品金額
1598
- 消費税額
1599
- 返品合計
1600
- 倉庫コード
1601
- 備考
1602
- 作成日時
1603
- 更新日時
1604
- }
1605
-
1606
- entity 返品明細 {
1607
- ID <<PK>>
1608
- --
1609
- 返品ID <<FK>>
1610
- 行番号
1611
- 売上明細ID <<FK>>
1612
- 商品コード <<FK>>
1613
- 商品名
1614
- 返品数量
1615
- 単位
1616
- 単価
1617
- 金額
1618
- 税区分
1619
- 消費税率
1620
- 消費税額
1621
- 備考
1622
- }
1623
-
1624
- 出荷データ ||--o| 売上データ
1625
- 売上データ ||--o{ 売上明細
1626
- 売上データ ||--o{ 返品データ
1627
- 返品データ ||--o{ 返品明細
1628
-
1629
- @enduml
1630
- ```
1631
-
1632
- ### 出荷完了から売上計上への流れ
1633
-
1634
- ```plantuml
1635
- @startuml
1636
-
1637
- title 出荷完了から売上計上への流れ
1638
-
1639
- |倉庫部門|
1640
- start
1641
- :出荷完了報告;
1642
- note right
1643
- 配送業者に引渡し
1644
- 追跡番号登録
1645
- end note
1646
-
1647
- |システム|
1648
- :出荷ステータス更新;
1649
- note right
1650
- 出荷済に変更
1651
- end note
1652
-
1653
- :売上データ自動生成;
1654
- note right
1655
- 出荷指示データを元に
1656
- 売上ヘッダ・明細を作成
1657
- end note
1658
-
1659
- :受注明細の出荷数量更新;
1660
-
1661
- if (全明細出荷完了?) then (yes)
1662
- :受注ステータスを出荷済に更新;
1663
- else (no)
1664
- :一部出荷として継続;
1665
- endif
1666
-
1667
- |営業部門|
1668
- :納品書発行;
1669
-
1670
- stop
1671
-
1672
- @enduml
1673
- ```
1674
-
1675
- ### 売上ステータスの定義
1676
-
1677
- | ステータス | 説明 |
1678
- |-----------|------|
1679
- | **計上済** | 売上が計上された状態 |
1680
- | **請求済** | 請求書が発行された状態 |
1681
- | **入金済** | 入金が確認された状態 |
1682
- | **取消** | 売上が取り消された状態 |
1683
-
1684
- ### マイグレーション:売上関連テーブルの作成
1685
-
1686
- <details>
1687
- <summary>V009__create_sales_tables.sql</summary>
1688
-
1689
- ```sql
1690
- -- src/main/resources/db/migration/V009__create_sales_tables.sql
1691
-
1692
- -- 売上ステータス
1693
- CREATE TYPE 売上ステータス AS ENUM ('計上済', '請求済', '入金済', 'キャンセル');
1694
-
1695
- -- 売上データ(ヘッダ)
1696
- CREATE TABLE "売上データ" (
1697
- "ID" SERIAL PRIMARY KEY,
1698
- "売上番号" VARCHAR(20) UNIQUE NOT NULL,
1699
- "売上日" DATE NOT NULL,
1700
- "受注ID" INTEGER NOT NULL,
1701
- "出荷ID" INTEGER,
1702
- "顧客コード" VARCHAR(20) NOT NULL,
1703
- "顧客枝番" VARCHAR(10) DEFAULT '00',
1704
- "担当者コード" VARCHAR(20),
1705
- "売上金額" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
1706
- "消費税額" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
1707
- "売上合計" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
1708
- "ステータス" 売上ステータス DEFAULT '計上済' NOT NULL,
1709
- "請求ID" INTEGER,
1710
- "備考" TEXT,
1711
- "作成日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
1712
- "作成者" VARCHAR(50),
1713
- "更新日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
1714
- "更新者" VARCHAR(50),
1715
- CONSTRAINT "fk_売上データ_受注"
1716
- FOREIGN KEY ("受注ID") REFERENCES "受注データ"("ID"),
1717
- CONSTRAINT "fk_売上データ_出荷"
1718
- FOREIGN KEY ("出荷ID") REFERENCES "出荷データ"("ID"),
1719
- CONSTRAINT "fk_売上データ_顧客"
1720
- FOREIGN KEY ("顧客コード", "顧客枝番") REFERENCES "顧客マスタ"("顧客コード", "顧客枝番")
1721
- );
1722
-
1723
- -- 売上明細
1724
- CREATE TABLE "売上明細" (
1725
- "ID" SERIAL PRIMARY KEY,
1726
- "売上ID" INTEGER NOT NULL,
1727
- "行番号" INTEGER NOT NULL,
1728
- "受注明細ID" INTEGER NOT NULL,
1729
- "出荷明細ID" INTEGER,
1730
- "商品コード" VARCHAR(20) NOT NULL,
1731
- "商品名" VARCHAR(100) NOT NULL,
1732
- "売上数量" DECIMAL(15, 2) NOT NULL,
1733
- "単位" VARCHAR(10),
1734
- "単価" DECIMAL(15, 2) NOT NULL,
1735
- "金額" DECIMAL(15, 2) NOT NULL,
1736
- "税区分" 税区分 DEFAULT '外税' NOT NULL,
1737
- "消費税率" DECIMAL(5, 2) DEFAULT 10.00 NOT NULL,
1738
- "消費税額" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
1739
- "備考" TEXT,
1740
- CONSTRAINT "fk_売上明細_売上"
1741
- FOREIGN KEY ("売上ID") REFERENCES "売上データ"("ID") ON DELETE CASCADE,
1742
- CONSTRAINT "fk_売上明細_受注明細"
1743
- FOREIGN KEY ("受注明細ID") REFERENCES "受注明細"("ID"),
1744
- CONSTRAINT "fk_売上明細_出荷明細"
1745
- FOREIGN KEY ("出荷明細ID") REFERENCES "出荷明細"("ID"),
1746
- CONSTRAINT "fk_売上明細_商品"
1747
- FOREIGN KEY ("商品コード") REFERENCES "商品マスタ"("商品コード"),
1748
- CONSTRAINT "uq_売上明細_行番号" UNIQUE ("売上ID", "行番号")
1749
- );
1750
-
1751
- -- インデックス
1752
- CREATE INDEX "idx_売上データ_受注ID" ON "売上データ"("受注ID");
1753
- CREATE INDEX "idx_売上データ_出荷ID" ON "売上データ"("出荷ID");
1754
- CREATE INDEX "idx_売上データ_顧客コード" ON "売上データ"("顧客コード");
1755
- CREATE INDEX "idx_売上データ_売上日" ON "売上データ"("売上日");
1756
- CREATE INDEX "idx_売上データ_ステータス" ON "売上データ"("ステータス");
1757
- ```
1758
-
1759
- </details>
1760
-
1761
- ### 売上ステータス Enum
1762
-
1763
- <details>
1764
- <summary>SalesStatus.java</summary>
1765
-
1766
- ```java
1767
- // src/main/java/com/example/sms/domain/model/sales/SalesStatus.java
1768
- package com.example.sms.domain.model.sales;
1769
-
1770
- import lombok.Getter;
1771
- import lombok.RequiredArgsConstructor;
1772
-
1773
- @Getter
1774
- @RequiredArgsConstructor
1775
- public enum SalesStatus {
1776
- RECORDED("計上済"),
1777
- INVOICED("請求済"),
1778
- COLLECTED("入金済"),
1779
- CANCELLED("キャンセル");
1780
-
1781
- private final String displayName;
1782
-
1783
- public static SalesStatus fromDisplayName(String displayName) {
1784
- for (SalesStatus status : values()) {
1785
- if (status.displayName.equals(displayName)) {
1786
- return status;
1787
- }
1788
- }
1789
- throw new IllegalArgumentException("Unknown sales status: " + displayName);
1790
- }
1791
- }
1792
- ```
1793
-
1794
- </details>
1795
-
1796
- ### 売上エンティティ
1797
-
1798
- <details>
1799
- <summary>Sales.java</summary>
1800
-
1801
- ```java
1802
- // src/main/java/com/example/sms/domain/model/sales/Sales.java
1803
- package com.example.sms.domain.model.sales;
1804
-
1805
- import lombok.AllArgsConstructor;
1806
- import lombok.Builder;
1807
- import lombok.Data;
1808
- import lombok.NoArgsConstructor;
1809
-
1810
- import java.math.BigDecimal;
1811
- import java.time.LocalDate;
1812
- import java.time.LocalDateTime;
1813
- import java.util.ArrayList;
1814
- import java.util.List;
1815
-
1816
- @Data
1817
- @Builder
1818
- @NoArgsConstructor
1819
- @AllArgsConstructor
1820
- @SuppressWarnings("PMD.RedundantFieldInitializer")
1821
- public class Sales {
1822
- private Integer id;
1823
- private String salesNumber;
1824
- private LocalDate salesDate;
1825
- private Integer orderId;
1826
- private Integer shipmentId;
1827
- private String customerCode;
1828
- private String customerBranchNumber;
1829
- private String representativeCode;
1830
- @Builder.Default
1831
- private BigDecimal salesAmount = BigDecimal.ZERO;
1832
- @Builder.Default
1833
- private BigDecimal taxAmount = BigDecimal.ZERO;
1834
- @Builder.Default
1835
- private BigDecimal totalAmount = BigDecimal.ZERO;
1836
- @Builder.Default
1837
- private SalesStatus status = SalesStatus.RECORDED;
1838
- private Integer invoiceId;
1839
- private String remarks;
1840
- private LocalDateTime createdAt;
1841
- private String createdBy;
1842
- private LocalDateTime updatedAt;
1843
- private String updatedBy;
1844
-
1845
- @Builder.Default
1846
- private List<SalesDetail> details = new ArrayList<>();
1847
- }
1848
- ```
1849
-
1850
- </details>
1851
-
1852
- <details>
1853
- <summary>SalesDetail.java</summary>
1854
-
1855
- ```java
1856
- // src/main/java/com/example/sms/domain/model/sales/SalesDetail.java
1857
- package com.example.sms.domain.model.sales;
1858
-
1859
- import com.example.sms.domain.model.product.TaxCategory;
1860
- import lombok.AllArgsConstructor;
1861
- import lombok.Builder;
1862
- import lombok.Data;
1863
- import lombok.NoArgsConstructor;
1864
-
1865
- import java.math.BigDecimal;
1866
-
1867
- @Data
1868
- @Builder
1869
- @NoArgsConstructor
1870
- @AllArgsConstructor
1871
- public class SalesDetail {
1872
- private Integer id;
1873
- private Integer salesId;
1874
- private Integer lineNumber;
1875
- private Integer orderDetailId;
1876
- private Integer shipmentDetailId;
1877
- private String productCode;
1878
- private String productName;
1879
- private BigDecimal salesQuantity;
1880
- private String unit;
1881
- private BigDecimal unitPrice;
1882
- private BigDecimal amount;
1883
- private TaxCategory taxCategory;
1884
- private BigDecimal taxRate;
1885
- private BigDecimal taxAmount;
1886
- private String remarks;
1887
- }
1888
- ```
1889
-
1890
- </details>
1891
-
1892
- ### 返品処理の設計
1893
-
1894
- 返品処理は、売上データに対してマイナスの取引を記録する処理です。
1895
-
1896
- #### 返品業務の流れ
1897
-
1898
- ```plantuml
1899
- @startuml
1900
-
1901
- title 返品業務フロー
1902
-
1903
- |営業担当|
1904
- start
1905
- :返品依頼受付;
1906
- note right
1907
- 顧客からの返品依頼
1908
- 理由の確認
1909
- end note
1910
-
1911
- :返品データ登録;
1912
-
1913
- |倉庫担当|
1914
- :返品商品受入;
1915
- :検品;
1916
-
1917
- if (商品状態OK?) then (yes)
1918
- :在庫戻入;
1919
- else (no)
1920
- :廃棄処理;
1921
- endif
1922
-
1923
- |経理担当|
1924
- :売上取消処理;
1925
- note right
1926
- 返品金額分の
1927
- 売上をマイナス計上
1928
- end note
1929
-
1930
- stop
1931
-
1932
- @enduml
1933
- ```
1934
-
1935
- ### マイグレーション:返品関連テーブルの作成
1936
-
1937
- <details>
1938
- <summary>V009__create_return_tables.sql</summary>
1939
-
1940
- ```sql
1941
- -- src/main/resources/db/migration/V009__create_return_tables.sql
1942
-
1943
- -- 返品データ
1944
- CREATE TABLE "返品データ" (
1945
- "ID" SERIAL PRIMARY KEY,
1946
- "返品番号" VARCHAR(20) UNIQUE NOT NULL,
1947
- "返品日" DATE NOT NULL,
1948
- "売上ID" INTEGER NOT NULL,
1949
- "顧客コード" VARCHAR(20) NOT NULL,
1950
- "返品理由" VARCHAR(200),
1951
- "返品金額" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
1952
- "消費税額" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
1953
- "返品合計" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
1954
- "倉庫コード" VARCHAR(20),
1955
- "備考" TEXT,
1956
- "作成日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
1957
- "作成者" VARCHAR(50),
1958
- "更新日時" TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
1959
- "更新者" VARCHAR(50),
1960
- CONSTRAINT "fk_返品データ_売上"
1961
- FOREIGN KEY ("売上ID") REFERENCES "売上データ"("ID"),
1962
- CONSTRAINT "fk_返品データ_顧客"
1963
- FOREIGN KEY ("顧客コード") REFERENCES "顧客マスタ"("顧客コード")
1964
- );
1965
-
1966
- -- 返品明細
1967
- CREATE TABLE "返品明細" (
1968
- "ID" SERIAL PRIMARY KEY,
1969
- "返品ID" INTEGER NOT NULL,
1970
- "行番号" INTEGER NOT NULL,
1971
- "売上明細ID" INTEGER NOT NULL,
1972
- "商品コード" VARCHAR(20) NOT NULL,
1973
- "商品名" VARCHAR(100) NOT NULL,
1974
- "返品数量" DECIMAL(15, 2) NOT NULL,
1975
- "単位" VARCHAR(10),
1976
- "単価" DECIMAL(15, 2) NOT NULL,
1977
- "金額" DECIMAL(15, 2) NOT NULL,
1978
- "税区分" 税区分 DEFAULT '外税' NOT NULL,
1979
- "消費税率" DECIMAL(5, 2) DEFAULT 10.00 NOT NULL,
1980
- "消費税額" DECIMAL(15, 2) DEFAULT 0 NOT NULL,
1981
- "備考" TEXT,
1982
- CONSTRAINT "fk_返品明細_返品"
1983
- FOREIGN KEY ("返品ID") REFERENCES "返品データ"("ID") ON DELETE CASCADE,
1984
- CONSTRAINT "fk_返品明細_売上明細"
1985
- FOREIGN KEY ("売上明細ID") REFERENCES "売上明細"("ID"),
1986
- CONSTRAINT "fk_返品明細_商品"
1987
- FOREIGN KEY ("商品コード") REFERENCES "商品マスタ"("商品コード"),
1988
- CONSTRAINT "uq_返品明細_行番号" UNIQUE ("返品ID", "行番号")
1989
- );
1990
-
1991
- -- インデックス
1992
- CREATE INDEX "idx_返品データ_売上ID" ON "返品データ"("売上ID");
1993
- CREATE INDEX "idx_返品データ_返品日" ON "返品データ"("返品日");
1994
- ```
1995
-
1996
- </details>
1997
-
1998
- ### 赤黒処理の考え方
1999
-
2000
- 赤黒処理とは、誤った伝票を訂正するための会計処理手法です。
2001
-
2002
- ```plantuml
2003
- @startuml
2004
-
2005
- title 赤黒処理の流れ
2006
-
2007
- participant "元伝票" as original
2008
- participant "赤伝票" as red
2009
- participant "黒伝票" as black
2010
-
2011
- note over original
2012
- 誤った内容の伝票
2013
- 金額: +10,000円
2014
- end note
2015
-
2016
- original -> red : 取消処理
2017
- note over red
2018
- 赤伝票(マイナス)
2019
- 金額: -10,000円
2020
- end note
2021
-
2022
- red -> black : 訂正処理
2023
- note over black
2024
- 黒伝票(正しい内容)
2025
- 金額: +12,000円
2026
- end note
2027
-
2028
- note over original, black
2029
- 最終結果:
2030
- 10,000 - 10,000 + 12,000 = 12,000円
2031
- end note
2032
-
2033
- @enduml
2034
- ```
2035
-
2036
- #### 赤黒処理の特徴
2037
-
2038
- | 項目 | 説明 |
2039
- |-----|------|
2040
- | **元伝票** | 訂正対象となる誤った伝票 |
2041
- | **赤伝票** | 元伝票をマイナスで打ち消す伝票 |
2042
- | **黒伝票** | 正しい内容を記載した新しい伝票 |
2043
-
2044
- #### 赤黒処理のメリット
2045
-
2046
- - **監査証跡の保持**: 元の伝票を削除せず、訂正の履歴が残る
2047
- - **会計基準への準拠**: 伝票の修正ではなく、新規伝票で訂正
2048
- - **トレーサビリティ**: いつ、誰が、なぜ訂正したかを追跡可能
2049
-
2050
- ---
2051
-
2052
- ## 6.4 全体の ER 図
2053
-
2054
- 受注から売上までの全体的な関連を示します。
2055
-
2056
- ```plantuml
2057
- @startuml
2058
-
2059
- title 受注・出荷・売上の全体ER図
2060
-
2061
- entity 顧客マスタ {
2062
- 顧客コード <<PK>>
2063
- --
2064
- 顧客名
2065
- ...
2066
- }
2067
-
2068
- entity 商品マスタ {
2069
- 商品コード <<PK>>
2070
- --
2071
- 商品名
2072
- 単価
2073
- ...
2074
- }
2075
-
2076
- entity 見積データ {
2077
- ID <<PK>>
2078
- 見積番号 <<UK>>
2079
- --
2080
- 見積日
2081
- 顧客コード <<FK>>
2082
- ステータス
2083
- ...
2084
- }
2085
-
2086
- entity 見積明細 {
2087
- ID <<PK>>
2088
- --
2089
- 見積ID <<FK>>
2090
- 商品コード <<FK>>
2091
- 数量
2092
- 単価
2093
- ...
2094
- }
2095
-
2096
- entity 受注データ {
2097
- ID <<PK>>
2098
- 受注番号 <<UK>>
2099
- --
2100
- 受注日
2101
- 顧客コード <<FK>>
2102
- 見積ID <<FK>>
2103
- ステータス
2104
- ...
2105
- }
2106
-
2107
- entity 受注明細 {
2108
- ID <<PK>>
2109
- --
2110
- 受注ID <<FK>>
2111
- 商品コード <<FK>>
2112
- 受注数量
2113
- 引当数量
2114
- 出荷数量
2115
- 残数量
2116
- ...
2117
- }
2118
-
2119
- entity 出荷指示データ {
2120
- ID <<PK>>
2121
- 出荷指示番号 <<UK>>
2122
- --
2123
- 受注ID <<FK>>
2124
- 顧客コード <<FK>>
2125
- ステータス
2126
- ...
2127
- }
2128
-
2129
- entity 出荷指示明細 {
2130
- ID <<PK>>
2131
- --
2132
- 出荷指示ID <<FK>>
2133
- 受注明細ID <<FK>>
2134
- 商品コード <<FK>>
2135
- 指示数量
2136
- 出荷数量
2137
- ...
2138
- }
2139
-
2140
- entity 売上データ {
2141
- ID <<PK>>
2142
- 売上番号 <<UK>>
2143
- --
2144
- 受注ID <<FK>>
2145
- 出荷指示ID <<FK>>
2146
- 顧客コード <<FK>>
2147
- ステータス
2148
- ...
2149
- }
2150
-
2151
- entity 売上明細 {
2152
- ID <<PK>>
2153
- --
2154
- 売上ID <<FK>>
2155
- 受注明細ID <<FK>>
2156
- 商品コード <<FK>>
2157
- 売上数量
2158
- 原価
2159
- 粗利
2160
- ...
2161
- }
2162
-
2163
- entity 返品データ {
2164
- ID <<PK>>
2165
- 返品番号 <<UK>>
2166
- --
2167
- 売上ID <<FK>>
2168
- 顧客コード <<FK>>
2169
- 返品理由
2170
- ...
2171
- }
2172
-
2173
- entity 返品明細 {
2174
- ID <<PK>>
2175
- --
2176
- 返品ID <<FK>>
2177
- 売上明細ID <<FK>>
2178
- 商品コード <<FK>>
2179
- 返品数量
2180
- ...
2181
- }
2182
-
2183
- 顧客マスタ ||--o{ 見積データ
2184
- 顧客マスタ ||--o{ 受注データ
2185
- 顧客マスタ ||--o{ 出荷指示データ
2186
- 顧客マスタ ||--o{ 売上データ
2187
- 顧客マスタ ||--o{ 返品データ
2188
-
2189
- 商品マスタ ||--o{ 見積明細
2190
- 商品マスタ ||--o{ 受注明細
2191
- 商品マスタ ||--o{ 出荷指示明細
2192
- 商品マスタ ||--o{ 売上明細
2193
- 商品マスタ ||--o{ 返品明細
2194
-
2195
- 見積データ ||--o{ 見積明細
2196
- 見積データ ||--o| 受注データ : "受注化"
2197
-
2198
- 受注データ ||--o{ 受注明細
2199
- 受注データ ||--o{ 出荷指示データ
2200
- 受注データ ||--o{ 売上データ
2201
-
2202
- 受注明細 ||--o{ 出荷指示明細
2203
- 受注明細 ||--o{ 売上明細
2204
-
2205
- 出荷指示データ ||--o{ 出荷指示明細
2206
- 出荷指示データ ||--o| 売上データ
2207
-
2208
- 売上データ ||--o{ 売上明細
2209
- 売上データ ||--o{ 返品データ
2210
-
2211
- 売上明細 ||--o{ 返品明細
2212
-
2213
- 返品データ ||--o{ 返品明細
2214
-
2215
- @enduml
2216
- ```
2217
-
2218
- ---
2219
-
2220
- ## 6.5 リレーションと楽観ロックの設計
2221
-
2222
- ### MyBatis ネストした ResultMap によるリレーション設定
2223
-
2224
- 受注データは、受注(ヘッダ)→ 受注明細の2層構造を持ちます。MyBatis でこの親子関係を効率的に取得するためのリレーション設定を実装します。
2225
-
2226
- #### ネストした ResultMap の定義
2227
-
2228
- <details>
2229
- <summary>SalesOrderMapper.xml(リレーション設定)</summary>
2230
-
2231
- ```xml
2232
- <?xml version="1.0" encoding="UTF-8" ?>
2233
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
2234
- "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
2235
-
2236
- <!-- src/main/resources/mapper/SalesOrderMapper.xml -->
2237
- <mapper namespace="com.example.sms.infrastructure.persistence.mapper.SalesOrderMapper">
2238
-
2239
- <!-- 受注(ヘッダ)の ResultMap -->
2240
- <resultMap id="salesOrderWithDetailsResultMap" type="com.example.sms.domain.model.sales.SalesOrder">
2241
- <id property="id" column="o_id"/>
2242
- <result property="orderNumber" column="o_受注番号"/>
2243
- <result property="orderDate" column="o_受注日"/>
2244
- <result property="customerCode" column="o_顧客コード"/>
2245
- <result property="shipToCode" column="o_出荷先コード"/>
2246
- <result property="salesRepCode" column="o_担当者コード"/>
2247
- <result property="requestedDeliveryDate" column="o_希望納期"/>
2248
- <result property="scheduledShipDate" column="o_出荷予定日"/>
2249
- <result property="subtotal" column="o_受注金額"/>
2250
- <result property="taxAmount" column="o_消費税額"/>
2251
- <result property="totalAmount" column="o_受注合計"/>
2252
- <result property="status" column="o_ステータス"
2253
- typeHandler="com.example.sms.infrastructure.out.persistence.typehandler.OrderStatusTypeHandler"/>
2254
- <result property="version" column="o_バージョン"/>
2255
- <result property="createdAt" column="o_作成日時"/>
2256
- <result property="updatedAt" column="o_更新日時"/>
2257
- <!-- 受注明細との1:N関連 -->
2258
- <collection property="details" ofType="com.example.sms.domain.model.sales.SalesOrderDetail"
2259
- resultMap="salesOrderDetailNestedResultMap"/>
2260
- </resultMap>
2261
-
2262
- <!-- 受注明細のネスト ResultMap -->
2263
- <resultMap id="salesOrderDetailNestedResultMap" type="com.example.sms.domain.model.sales.SalesOrderDetail">
2264
- <id property="id" column="d_id"/>
2265
- <result property="orderId" column="d_受注ID"/>
2266
- <result property="lineNumber" column="d_行番号"/>
2267
- <result property="productCode" column="d_商品コード"/>
2268
- <result property="productName" column="d_商品名"/>
2269
- <result property="orderQuantity" column="d_受注数量"/>
2270
- <result property="allocatedQuantity" column="d_引当数量"/>
2271
- <result property="shippedQuantity" column="d_出荷数量"/>
2272
- <result property="remainingQuantity" column="d_残数量"/>
2273
- <result property="unit" column="d_単位"/>
2274
- <result property="unitPrice" column="d_単価"/>
2275
- <result property="amount" column="d_金額"/>
2276
- <result property="taxCategory" column="d_税区分"
2277
- typeHandler="com.example.sms.infrastructure.out.persistence.typehandler.TaxCategoryTypeHandler"/>
2278
- <result property="taxRate" column="d_消費税率"/>
2279
- <result property="taxAmount" column="d_消費税額"/>
2280
- <result property="version" column="d_バージョン"/>
2281
- </resultMap>
2282
-
2283
- <!-- JOIN による一括取得クエリ -->
2284
- <select id="findWithDetailsByOrderNumber" resultMap="salesOrderWithDetailsResultMap">
2285
- SELECT
2286
- o."ID" AS o_id,
2287
- o."受注番号" AS o_受注番号,
2288
- o."受注日" AS o_受注日,
2289
- o."顧客コード" AS o_顧客コード,
2290
- o."出荷先コード" AS o_出荷先コード,
2291
- o."担当者コード" AS o_担当者コード,
2292
- o."希望納期" AS o_希望納期,
2293
- o."出荷予定日" AS o_出荷予定日,
2294
- o."受注金額" AS o_受注金額,
2295
- o."消費税額" AS o_消費税額,
2296
- o."受注合計" AS o_受注合計,
2297
- o."ステータス" AS o_ステータス,
2298
- o."バージョン" AS o_バージョン,
2299
- o."作成日時" AS o_作成日時,
2300
- o."更新日時" AS o_更新日時,
2301
- d."ID" AS d_id,
2302
- d."受注ID" AS d_受注ID,
2303
- d."行番号" AS d_行番号,
2304
- d."商品コード" AS d_商品コード,
2305
- d."商品名" AS d_商品名,
2306
- d."受注数量" AS d_受注数量,
2307
- d."引当数量" AS d_引当数量,
2308
- d."出荷数量" AS d_出荷数量,
2309
- d."残数量" AS d_残数量,
2310
- d."単位" AS d_単位,
2311
- d."単価" AS d_単価,
2312
- d."金額" AS d_金額,
2313
- d."税区分" AS d_税区分,
2314
- d."消費税率" AS d_消費税率,
2315
- d."消費税額" AS d_消費税額,
2316
- d."バージョン" AS d_バージョン
2317
- FROM "受注データ" o
2318
- LEFT JOIN "受注明細" d
2319
- ON o."ID" = d."受注ID"
2320
- WHERE o."受注番号" = #{orderNumber}
2321
- ORDER BY d."行番号"
2322
- </select>
2323
-
2324
- </mapper>
2325
- ```
2326
-
2327
- </details>
2328
-
2329
- #### リレーション設定のポイント
2330
-
2331
- | 設定項目 | 説明 |
2332
- |---------|------|
2333
- | `<collection>` | 1:N 関連のマッピング |
2334
- | `<id>` | 主キーの識別(MyBatis が重複排除に使用) |
2335
- | `resultMap` | ネストした ResultMap の参照 |
2336
- | エイリアス(AS) | カラム名の重複を避けるためのプレフィックス |
2337
- | `ORDER BY` | コレクションの順序を保証 |
2338
-
2339
- ### 楽観ロックの実装
2340
-
2341
- 複数ユーザーが同時に受注データを編集する場合、データの整合性を保つために楽観ロック(Optimistic Locking)を実装します。
2342
-
2343
- #### Flyway マイグレーション: バージョンカラム追加
2344
-
2345
- <details>
2346
- <summary>V010__add_version_columns.sql</summary>
2347
-
2348
- ```sql
2349
- -- src/main/resources/db/migration/V010__add_version_columns.sql
2350
-
2351
- -- 受注データテーブルにバージョンカラムを追加
2352
- ALTER TABLE "受注データ" ADD COLUMN "バージョン" INTEGER DEFAULT 1 NOT NULL;
2353
-
2354
- -- 受注明細テーブルにバージョンカラムを追加
2355
- ALTER TABLE "受注明細" ADD COLUMN "バージョン" INTEGER DEFAULT 1 NOT NULL;
2356
-
2357
- -- 出荷指示データテーブルにバージョンカラムを追加
2358
- ALTER TABLE "出荷指示データ" ADD COLUMN "バージョン" INTEGER DEFAULT 1 NOT NULL;
2359
-
2360
- -- 出荷指示明細テーブルにバージョンカラムを追加
2361
- ALTER TABLE "出荷指示明細" ADD COLUMN "バージョン" INTEGER DEFAULT 1 NOT NULL;
2362
-
2363
- -- 売上データテーブルにバージョンカラムを追加
2364
- ALTER TABLE "売上データ" ADD COLUMN "バージョン" INTEGER DEFAULT 1 NOT NULL;
2365
-
2366
- -- 売上明細テーブルにバージョンカラムを追加
2367
- ALTER TABLE "売上明細" ADD COLUMN "バージョン" INTEGER DEFAULT 1 NOT NULL;
2368
-
2369
- -- 返品データテーブルにバージョンカラムを追加
2370
- ALTER TABLE "返品データ" ADD COLUMN "バージョン" INTEGER DEFAULT 1 NOT NULL;
2371
-
2372
- -- 返品明細テーブルにバージョンカラムを追加
2373
- ALTER TABLE "返品明細" ADD COLUMN "バージョン" INTEGER DEFAULT 1 NOT NULL;
2374
-
2375
- -- コメント追加
2376
- COMMENT ON COLUMN "受注データ"."バージョン" IS '楽観ロック用バージョン番号';
2377
- COMMENT ON COLUMN "受注明細"."バージョン" IS '楽観ロック用バージョン番号';
2378
- COMMENT ON COLUMN "出荷指示データ"."バージョン" IS '楽観ロック用バージョン番号';
2379
- COMMENT ON COLUMN "出荷指示明細"."バージョン" IS '楽観ロック用バージョン番号';
2380
- COMMENT ON COLUMN "売上データ"."バージョン" IS '楽観ロック用バージョン番号';
2381
- COMMENT ON COLUMN "売上明細"."バージョン" IS '楽観ロック用バージョン番号';
2382
- COMMENT ON COLUMN "返品データ"."バージョン" IS '楽観ロック用バージョン番号';
2383
- COMMENT ON COLUMN "返品明細"."バージョン" IS '楽観ロック用バージョン番号';
2384
- ```
2385
-
2386
- </details>
2387
-
2388
- #### エンティティへのバージョンフィールド追加
2389
-
2390
- <details>
2391
- <summary>SalesOrder.java(バージョンフィールド追加)</summary>
2392
-
2393
- ```java
2394
- // src/main/java/com/example/sms/domain/model/sales/SalesOrder.java
2395
- package com.example.sms.domain.model.sales;
2396
-
2397
- import lombok.AllArgsConstructor;
2398
- import lombok.Builder;
2399
- import lombok.Data;
2400
- import lombok.NoArgsConstructor;
2401
-
2402
- import java.math.BigDecimal;
2403
- import java.time.LocalDate;
2404
- import java.time.LocalDateTime;
2405
- import java.util.ArrayList;
2406
- import java.util.List;
2407
-
2408
- @Data
2409
- @Builder
2410
- @NoArgsConstructor
2411
- @AllArgsConstructor
2412
- public class SalesOrder {
2413
- private Integer id;
2414
- private String orderNumber;
2415
- private LocalDate orderDate;
2416
- private String customerCode;
2417
- private String shipToCode;
2418
- private String salesRepCode;
2419
- private LocalDate requestedDeliveryDate;
2420
- private LocalDate scheduledShipDate;
2421
- private BigDecimal subtotal;
2422
- private BigDecimal taxAmount;
2423
- private BigDecimal totalAmount;
2424
- private OrderStatus status;
2425
- private Integer quotationId;
2426
- private String customerOrderNumber;
2427
- private String remarks;
2428
- private LocalDateTime createdAt;
2429
- private String createdBy;
2430
- private LocalDateTime updatedAt;
2431
- private String updatedBy;
2432
-
2433
- // 楽観ロック用バージョン
2434
- @Builder.Default
2435
- private Integer version = 1;
2436
-
2437
- // リレーション
2438
- @Builder.Default
2439
- private List<SalesOrderDetail> details = new ArrayList<>();
2440
- }
2441
- ```
2442
-
2443
- </details>
2444
-
2445
- #### MyBatis Mapper: 楽観ロック対応の更新
2446
-
2447
- <details>
2448
- <summary>SalesOrderMapper.xml(楽観ロック対応 UPDATE)</summary>
2449
-
2450
- ```xml
2451
- <!-- 楽観ロック対応の更新(バージョンチェック付き) -->
2452
- <update id="updateWithOptimisticLock" parameterType="com.example.sms.domain.model.sales.SalesOrder">
2453
- UPDATE "受注データ"
2454
- SET
2455
- "受注日" = #{orderDate},
2456
- "顧客コード" = #{customerCode},
2457
- "出荷先コード" = #{shipToCode},
2458
- "担当者コード" = #{salesRepCode},
2459
- "希望納期" = #{requestedDeliveryDate},
2460
- "出荷予定日" = #{scheduledShipDate},
2461
- "受注金額" = #{subtotal},
2462
- "消費税額" = #{taxAmount},
2463
- "受注合計" = #{totalAmount},
2464
- "ステータス" = #{status, typeHandler=com.example.sms.infrastructure.out.persistence.typehandler.OrderStatusTypeHandler},
2465
- "更新日時" = CURRENT_TIMESTAMP,
2466
- "バージョン" = "バージョン" + 1
2467
- WHERE "ID" = #{id}
2468
- AND "バージョン" = #{version}
2469
- </update>
2470
- ```
2471
-
2472
- </details>
2473
-
2474
- #### 楽観ロック例外クラス
2475
-
2476
- <details>
2477
- <summary>OptimisticLockException.java</summary>
2478
-
2479
- ```java
2480
- // src/main/java/com/example/sms/domain/exception/OptimisticLockException.java
2481
- package com.example.sms.domain.exception;
2482
-
2483
- public class OptimisticLockException extends RuntimeException {
2484
-
2485
- private final String entityName;
2486
- private final Integer entityId;
2487
- private final Integer expectedVersion;
2488
- private final Integer actualVersion;
2489
-
2490
- public OptimisticLockException(String entityName, Integer entityId) {
2491
- super(String.format("%s (ID: %d) は既に削除されています", entityName, entityId));
2492
- this.entityName = entityName;
2493
- this.entityId = entityId;
2494
- this.expectedVersion = null;
2495
- this.actualVersion = null;
2496
- }
2497
-
2498
- public OptimisticLockException(String entityName, Integer entityId,
2499
- Integer expectedVersion, Integer actualVersion) {
2500
- super(String.format("%s (ID: %d) は他のユーザーによって更新されています。" +
2501
- "期待バージョン: %d, 実際のバージョン: %d",
2502
- entityName, entityId, expectedVersion, actualVersion));
2503
- this.entityName = entityName;
2504
- this.entityId = entityId;
2505
- this.expectedVersion = expectedVersion;
2506
- this.actualVersion = actualVersion;
2507
- }
2508
-
2509
- public String getEntityName() {
2510
- return entityName;
2511
- }
2512
-
2513
- public Integer getEntityId() {
2514
- return entityId;
2515
- }
2516
-
2517
- public Integer getExpectedVersion() {
2518
- return expectedVersion;
2519
- }
2520
-
2521
- public Integer getActualVersion() {
2522
- return actualVersion;
2523
- }
2524
- }
2525
- ```
2526
-
2527
- </details>
2528
-
2529
- #### Repository 実装: 楽観ロック対応
2530
-
2531
- <details>
2532
- <summary>SalesOrderRepositoryImpl.java(楽観ロック対応)</summary>
2533
-
2534
- ```java
2535
- // src/main/java/com/example/sms/infrastructure/persistence/repository/SalesOrderRepositoryImpl.java
2536
- package com.example.sms.infrastructure.persistence.repository;
2537
-
2538
- import com.example.sms.application.port.out.SalesOrderRepository;
2539
- import com.example.sms.domain.exception.OptimisticLockException;
2540
- import com.example.sms.domain.model.sales.OrderStatus;
2541
- import com.example.sms.domain.model.sales.SalesOrder;
2542
- import com.example.sms.domain.model.sales.SalesOrderDetail;
2543
- import com.example.sms.infrastructure.persistence.mapper.SalesOrderMapper;
2544
- import lombok.RequiredArgsConstructor;
2545
- import org.springframework.stereotype.Repository;
2546
- import org.springframework.transaction.annotation.Transactional;
2547
-
2548
- import java.math.BigDecimal;
2549
- import java.time.LocalDate;
2550
- import java.util.List;
2551
- import java.util.Optional;
2552
-
2553
- @Repository
2554
- @RequiredArgsConstructor
2555
- public class SalesOrderRepositoryImpl implements SalesOrderRepository {
2556
-
2557
- private final SalesOrderMapper mapper;
2558
-
2559
- @Override
2560
- @Transactional
2561
- public void update(SalesOrder order) {
2562
- int updatedCount = mapper.updateWithOptimisticLock(order);
2563
-
2564
- if (updatedCount == 0) {
2565
- // バージョン不一致または削除済み
2566
- Integer currentVersion = mapper.findVersionById(order.getId());
2567
- if (currentVersion == null) {
2568
- throw new OptimisticLockException("受注", order.getId());
2569
- } else {
2570
- throw new OptimisticLockException("受注", order.getId(),
2571
- order.getVersion(), currentVersion);
2572
- }
2573
- }
2574
- }
2575
-
2576
- @Override
2577
- public Optional<SalesOrder> findByIdWithDetails(Integer id) {
2578
- return Optional.ofNullable(mapper.findByIdWithDetails(id));
2579
- }
2580
-
2581
- @Override
2582
- public Optional<SalesOrder> findByOrderNumber(String orderNumber) {
2583
- return Optional.ofNullable(mapper.findByOrderNumber(orderNumber));
2584
- }
2585
-
2586
- // その他のメソッド...
2587
- }
2588
- ```
2589
-
2590
- </details>
2591
-
2592
- #### TDD: 楽観ロックのテスト
2593
-
2594
- <details>
2595
- <summary>SalesOrderRepositoryOptimisticLockTest.java</summary>
2596
-
2597
- ```java
2598
- // src/test/java/com/example/sms/infrastructure/persistence/repository/SalesOrderRepositoryOptimisticLockTest.java
2599
- package com.example.sms.infrastructure.persistence.repository;
2600
-
2601
- import com.example.sms.application.port.out.SalesOrderRepository;
2602
- import com.example.sms.domain.exception.OptimisticLockException;
2603
- import com.example.sms.domain.model.sales.OrderStatus;
2604
- import com.example.sms.domain.model.sales.SalesOrder;
2605
- import com.example.sms.testsetup.BaseIntegrationTest;
2606
- import org.junit.jupiter.api.*;
2607
- import org.springframework.beans.factory.annotation.Autowired;
2608
-
2609
- import java.math.BigDecimal;
2610
- import java.time.LocalDate;
2611
-
2612
- import static org.assertj.core.api.Assertions.*;
2613
-
2614
- @DisplayName("受注リポジトリ - 楽観ロック")
2615
- class SalesOrderRepositoryOptimisticLockTest extends BaseIntegrationTest {
2616
-
2617
- @Autowired
2618
- private SalesOrderRepository salesOrderRepository;
2619
-
2620
- @BeforeEach
2621
- void setUp() {
2622
- salesOrderRepository.deleteAll();
2623
- }
2624
-
2625
- @Nested
2626
- @DisplayName("楽観ロック")
2627
- class OptimisticLocking {
2628
-
2629
- @Test
2630
- @DisplayName("同じバージョンで更新できる")
2631
- void canUpdateWithSameVersion() {
2632
- // Arrange
2633
- var order = SalesOrder.builder()
2634
- .orderNumber("SO-2025-0001")
2635
- .orderDate(LocalDate.of(2025, 1, 20))
2636
- .customerCode("CUST-001")
2637
- .subtotal(new BigDecimal("50000"))
2638
- .taxAmount(new BigDecimal("5000"))
2639
- .totalAmount(new BigDecimal("55000"))
2640
- .status(OrderStatus.RECEIVED)
2641
- .build();
2642
- salesOrderRepository.save(order);
2643
-
2644
- // Act
2645
- var fetched = salesOrderRepository.findByOrderNumber("SO-2025-0001").get();
2646
- fetched.setSubtotal(new BigDecimal("60000"));
2647
- salesOrderRepository.update(fetched);
2648
-
2649
- // Assert
2650
- var updated = salesOrderRepository.findByOrderNumber("SO-2025-0001").get();
2651
- assertThat(updated.getSubtotal()).isEqualByComparingTo(new BigDecimal("60000"));
2652
- assertThat(updated.getVersion()).isEqualTo(2); // バージョンがインクリメント
2653
- }
2654
-
2655
- @Test
2656
- @DisplayName("異なるバージョンで更新すると楽観ロック例外が発生する")
2657
- void throwsExceptionWhenVersionMismatch() {
2658
- // Arrange
2659
- var order = SalesOrder.builder()
2660
- .orderNumber("SO-2025-0002")
2661
- .orderDate(LocalDate.of(2025, 1, 20))
2662
- .customerCode("CUST-001")
2663
- .subtotal(new BigDecimal("50000"))
2664
- .taxAmount(new BigDecimal("5000"))
2665
- .totalAmount(new BigDecimal("55000"))
2666
- .status(OrderStatus.RECEIVED)
2667
- .build();
2668
- salesOrderRepository.save(order);
2669
-
2670
- // ユーザーAが取得
2671
- var orderA = salesOrderRepository.findByOrderNumber("SO-2025-0002").get();
2672
- // ユーザーBが取得
2673
- var orderB = salesOrderRepository.findByOrderNumber("SO-2025-0002").get();
2674
-
2675
- // ユーザーAが更新(成功)
2676
- orderA.setSubtotal(new BigDecimal("60000"));
2677
- salesOrderRepository.update(orderA);
2678
-
2679
- // Act & Assert: ユーザーBが古いバージョンで更新(失敗)
2680
- orderB.setSubtotal(new BigDecimal("70000"));
2681
- assertThatThrownBy(() -> salesOrderRepository.update(orderB))
2682
- .isInstanceOf(OptimisticLockException.class)
2683
- .hasMessageContaining("他のユーザーによって更新されています");
2684
- }
2685
- }
2686
- }
2687
- ```
2688
-
2689
- </details>
2690
-
2691
- #### 楽観ロックのベストプラクティス
2692
-
2693
- | ポイント | 説明 |
2694
- |---------|------|
2695
- | **バージョンカラム** | INTEGER 型で十分(オーバーフローは実用上問題なし) |
2696
- | **WHERE 条件** | 必ず `AND "バージョン" = #{version}` を含める |
2697
- | **インクリメント** | `"バージョン" = "バージョン" + 1` でアトミックに更新 |
2698
- | **例外処理** | 更新件数が0の場合は楽観ロック例外をスロー |
2699
- | **リトライ** | 必要に応じて再取得・再更新のリトライロジックを実装 |
2700
-
2701
- ---
2702
-
2703
- ## まとめ
2704
-
2705
- 本章では、販売管理システムの中核となるトランザクションデータの設計を行いました。
2706
-
2707
- ### 設計のポイント
2708
-
2709
- 1. **ヘッダ・明細構造**: すべてのトランザクションデータは、ヘッダ(親)と明細(子)の1対多構造を持つ
2710
-
2711
- 2. **ステータス管理**: 各トランザクションは状態遷移を持ち、PostgreSQL の ENUM 型で管理
2712
-
2713
- 3. **トレーサビリティ**: 見積→受注→出荷→売上の流れを追跡可能な外部キー設計
2714
-
2715
- 4. **数量管理**: 受注明細では受注数量・引当数量・出荷数量・残数量を分離管理
2716
-
2717
- 5. **返品・赤黒処理**: 売上の訂正は削除ではなく、返品データによる追記で対応
2718
-
2719
- 6. **リレーション設定**: MyBatis のネスト ResultMap で親子関係を効率的に取得
2720
-
2721
- 7. **楽観ロック**: バージョンカラムによる同時更新制御で整合性を保証
2722
-
2723
- ### 次章の予告
2724
-
2725
- 第7章では、売上データを起点とした債権管理(請求・入金)の設計を行います。