mirror of
https://github.com/cursos-uai/sap_tfi_2026.git
synced 2026-07-31 20:48:30 -03:00
feat(patrones): patron Composite aplicado a Lista de Materiales (BoM)
Nuevo diagrama D-PAT-COMPOSITE-001 + documento siguiendo el estandar
FCEIA-UNR (Cristia, 2015) para documentar patrones de diseno.
Contenido:
1. Diagrama de clases Composite (PlantUML):
- Patron Composite puro (Component, Leaf, Composite)
- Aplicacion concreta a Odoo 19.0:
* Component = BomComponent (interfaz abstracta Python)
* Leaf = product.product
* Composite = mrp.bom
* children = bom_line_ids (One2many)
* Operation = explode(product, quantity)
* add = _onchange_product_id()
* remove = unlink() (CRUD Odoo)
* getChild = _compute_child_bom_id()
2. Documento docs/12_patrones_diseno/composite_bom.md con:
- Documentacion Pattern ... based on Composite because ...
- Seccion where mapeando cada elemento patron a elemento diseno
- Seccion comments explicando las decisiones
- Tabla completa de mapeo Pattern Element -> Diseno Element
- Analisis de cambios admitidos y anticipados
- Variantes del patron en la implementacion
- Justificacion detallada
- EV-COD-031..038 verificando contra codigo real
Archivos:
- diagrams/plantuml/d_pat_composite_001_bom.puml
- diagrams/png/D-PAT-COMPOSITE-001 ... .png
- diagrams/svg/D-PAT-COMPOSITE-001 ... .svg
- diagrams/pdf/D-PAT-COMPOSITE-001 ... .pdf
- docs/12_patrones_diseno/composite_bom.md
This commit is contained in:
BIN
Binary file not shown.
@@ -0,0 +1,121 @@
|
||||
@startuml D-PAT-COMPOSITE-001 — Patron Composite aplicado a Lista de Materiales (BoM)
|
||||
|
||||
title SAP-TFI-2026 — Patron Composite aplicado a Lista de Materiales (BoM) en Odoo 19.0
|
||||
|
||||
skinparam shadowing false
|
||||
skinparam handwritten false
|
||||
skinparam defaultFontName Arial
|
||||
skinparam defaultFontSize 11
|
||||
skinparam linetype ortho
|
||||
skinparam backgroundColor white
|
||||
skinparam classAttributeIconSize 0
|
||||
skinparam packageStyle rectangle
|
||||
|
||||
' ──────────────────── Patron Composite (GoF) ────────────────────
|
||||
|
||||
package "Patron Composite (GoF)" {
|
||||
abstract class "Component" as Comp {
|
||||
+operation()
|
||||
+add(Component)
|
||||
+remove(Component)
|
||||
+getChild(int)
|
||||
}
|
||||
|
||||
class "Leaf" as Leaf {
|
||||
+operation()
|
||||
}
|
||||
|
||||
class "Composite" as CompClass {
|
||||
-children: List<Component>
|
||||
+operation()
|
||||
+add(Component)
|
||||
+remove(Component)
|
||||
+getChild(int)
|
||||
}
|
||||
|
||||
Comp <|-- Leaf
|
||||
Comp <|-- CompClass
|
||||
CompClass "1" *-- "*" Comp : children
|
||||
}
|
||||
|
||||
' ──────────────────── Aplicacion al BoM de Odoo ────────────────────
|
||||
|
||||
package "Aplicacion: BoM (Bill of Materials) en Odoo 19.0" {
|
||||
|
||||
abstract class "<BomComponent>\nabstract (interfaz Python)" as BomComp {
|
||||
+get_product_id() : product.product
|
||||
+get_quantity() : Float
|
||||
+get_uom() : uom.uom
|
||||
+get_cost() : Float
|
||||
+explode(level) : List
|
||||
+accept(visitor)
|
||||
}
|
||||
|
||||
class "<mrp.bom>\n(Producto Compuesto)" as MrpBom {
|
||||
+_name = 'mrp.bom'
|
||||
+product_tmpl_id : Many2one(product.template)
|
||||
+product_id : Many2one(product.product)
|
||||
+bom_line_ids : One2many(mrp.bom.line)
|
||||
+product_qty : Float
|
||||
+product_uom_id : Many2one(uom.uom)
|
||||
--
|
||||
+explode(product, quantity)
|
||||
+_check_bom_cycle()
|
||||
+action_compute_price()
|
||||
}
|
||||
|
||||
class "<mrp.bom.line>\n(Línea Componente)" as MrpBomLine {
|
||||
+_name = 'mrp.bom.line'
|
||||
+product_id : Many2one(product.product)
|
||||
+bom_id : Many2one(mrp.bom)
|
||||
+child_bom_id : Many2one(mrp.bom, computed)
|
||||
+product_qty : Float
|
||||
+product_uom_id : Many2one(uom.uom)
|
||||
--
|
||||
+onchange_product_id()
|
||||
+_skip_bom_line()
|
||||
}
|
||||
|
||||
class "<product.product>\n(Producto Hoja)" as ProductProduct {
|
||||
+_name = 'product.product'
|
||||
+name : Char
|
||||
+list_price : Float
|
||||
+standard_price : Float
|
||||
+bom_ids : One2many(mrp.bom)
|
||||
--
|
||||
+get_cost()
|
||||
+explode_as_leaf()
|
||||
}
|
||||
|
||||
BomComp <|-- MrpBom
|
||||
BomComp <|-- MrpBomLine
|
||||
BomComp <|-- ProductProduct
|
||||
|
||||
MrpBom "1" *-- "*" MrpBomLine : bom_line_ids
|
||||
MrpBomLine "*" --> "0..1" MrpBom : child_bom_id (computed)
|
||||
MrpBomLine "*" --> "1" ProductProduct : product_id
|
||||
ProductProduct "1" *-- "*" MrpBom : bom_ids
|
||||
}
|
||||
|
||||
legend right
|
||||
Proyecto: SAP-TFI-2026
|
||||
Agente: saptfi2026
|
||||
Patron: Composite (Gamma et al., 2003)
|
||||
Aplicado a: Lista de Materiales (BoM) en Odoo 19.0
|
||||
Motivacion: estructura jerarquica de productos donde
|
||||
un producto puede estar compuesto por otros productos
|
||||
(recursivamente).
|
||||
|
||||
Beneficios:
|
||||
- Cliente trata uniforme Leaf y Composite
|
||||
- Composicion recursiva (BOM anidados)
|
||||
- Operaciones polimorficas (explode, get_cost)
|
||||
- Validacion de ciclos (_check_bom_cycle)
|
||||
|
||||
Trade-offs:
|
||||
- Puede violar LSP si Leaf no soporta add/remove
|
||||
- Dificil restringir tipo de hijos
|
||||
- Ciclos deben validarse explicitamente
|
||||
endlegend
|
||||
|
||||
@enduml
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
+270
@@ -0,0 +1,270 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="1106px" preserveAspectRatio="none" style="width:754px;height:1106px;background:#FFFFFF;" version="1.1" viewBox="0 0 754 1106" width="754px" zoomAndPan="magnify"><defs/><g><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="486" x="127.5" y="10.2104">SAP-TFI-2026 — Patron Composite aplicado a Lista de Materiales (BoM) en Odoo 19.0</text><!--MD5=[4cb06e9fe03ae72ec6bf330358d545e6]
|
||||
cluster Patron Composite (GoF)--><rect fill="#FFFFFF" height="356" style="stroke:#000000;stroke-width:1.5;" width="323" x="7" y="36.3047"/><text fill="#000000" font-family="Arial" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="153" x="92" y="48.5151">Patron Composite (GoF)</text><!--MD5=[4cc082bca42b639f0b3df5e7ab2b5e84]
|
||||
cluster Aplicacion: BoM (Bill of Materials) en Odoo 19.0--><rect fill="#FFFFFF" height="817" style="stroke:#000000;stroke-width:1.5;" width="394" x="354" y="19.8047"/><text fill="#000000" font-family="Arial" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="308" x="397" y="32.0151">Aplicacion: BoM (Bill of Materials) en Odoo 19.0</text><!--MD5=[5917aac93b048b898a3726acf879b0df]
|
||||
class Comp--><rect codeLine="16" fill="#FEFECE" height="95.2188" id="Comp" style="stroke:#A80036;stroke-width:1.5;" width="137" x="159.5" y="67.3047"/><ellipse cx="192.3" cy="81.3047" fill="#A9DCDF" rx="9" ry="9" style="stroke:#A80036;stroke-width:1.0;"/><path d="M191.6125,78.2422 L190.8625,81.5234 L192.3625,81.5234 L191.6125,78.2422 Z M190.6438,76.7891 L192.5813,76.7891 L194.7531,84.8047 L193.1594,84.8047 L192.6594,82.8203 L190.55,82.8203 L190.0656,84.8047 L188.4719,84.8047 L190.6438,76.7891 Z " fill="#000000"/><text fill="#000000" font-family="Arial" font-size="11" font-style="italic" lengthAdjust="spacing" textLength="65" x="208.7" y="85.1128">Component</text><line style="stroke:#A80036;stroke-width:1.5;" x1="160.5" x2="295.5" y1="95.3047" y2="95.3047"/><line style="stroke:#A80036;stroke-width:1.5;" x1="160.5" x2="295.5" y1="103.3047" y2="103.3047"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="71" x="165.5" y="117.5151">+operation()</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="103" x="165.5" y="130.3198">+add(Component)</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="125" x="165.5" y="143.1245">+remove(Component)</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="77" x="165.5" y="155.9292">+getChild(int)</text><!--MD5=[3670a9b67b8a752f6e42da25dea7e2da]
|
||||
class Leaf--><rect codeLine="23" fill="#FEFECE" height="56.8047" id="Leaf" style="stroke:#A80036;stroke-width:1.5;" width="83" x="23.5" y="293.8047"/><ellipse cx="50.45" cy="307.8047" fill="#ADD1B2" rx="9" ry="9" style="stroke:#A80036;stroke-width:1.0;"/><path d="M51.7625,311.5703 Q51.3875,311.7734 50.9656,311.8672 Q50.5594,311.9609 50.0906,311.9609 Q48.4813,311.9609 47.6219,310.8984 Q46.7625,309.8203 46.7625,307.8047 Q46.7625,305.7734 47.6219,304.7109 Q48.4813,303.6328 50.0906,303.6328 Q50.5594,303.6328 50.9656,303.7422 Q51.3875,303.8359 51.7625,304.0234 L51.7625,305.7891 Q51.3406,305.4141 50.95,305.2422 Q50.575,305.0703 50.1688,305.0703 Q49.3094,305.0703 48.8563,305.7578 Q48.4188,306.4453 48.4188,307.8047 Q48.4188,309.1641 48.8563,309.8516 Q49.3094,310.5391 50.1688,310.5391 Q50.575,310.5391 50.95,310.3672 Q51.3406,310.1953 51.7625,309.8047 L51.7625,311.5703 Z " fill="#000000"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="24" x="65.55" y="311.6128">Leaf</text><line style="stroke:#A80036;stroke-width:1.5;" x1="24.5" x2="105.5" y1="321.8047" y2="321.8047"/><line style="stroke:#A80036;stroke-width:1.5;" x1="24.5" x2="105.5" y1="329.8047" y2="329.8047"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="71" x="29.5" y="344.0151">+operation()</text><!--MD5=[da2ebf194dcbbe384d56885c58080451]
|
||||
class CompClass--><rect codeLine="27" fill="#FEFECE" height="108.0234" id="CompClass" style="stroke:#A80036;stroke-width:1.5;" width="172" x="142" y="268.3047"/><ellipse cx="193.75" cy="282.3047" fill="#ADD1B2" rx="9" ry="9" style="stroke:#A80036;stroke-width:1.0;"/><path d="M195.0625,286.0703 Q194.6875,286.2734 194.2656,286.3672 Q193.8594,286.4609 193.3906,286.4609 Q191.7813,286.4609 190.9219,285.3984 Q190.0625,284.3203 190.0625,282.3047 Q190.0625,280.2734 190.9219,279.2109 Q191.7813,278.1328 193.3906,278.1328 Q193.8594,278.1328 194.2656,278.2422 Q194.6875,278.3359 195.0625,278.5234 L195.0625,280.2891 Q194.6406,279.9141 194.25,279.7422 Q193.875,279.5703 193.4688,279.5703 Q192.6094,279.5703 192.1563,280.2578 Q191.7188,280.9453 191.7188,282.3047 Q191.7188,283.6641 192.1563,284.3516 Q192.6094,285.0391 193.4688,285.0391 Q193.875,285.0391 194.25,284.8672 Q194.6406,284.6953 195.0625,284.3047 L195.0625,286.0703 Z " fill="#000000"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="61" x="211.25" y="286.1128">Composite</text><line style="stroke:#A80036;stroke-width:1.5;" x1="143" x2="313" y1="296.3047" y2="296.3047"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="160" x="148" y="310.5151">-children: List<Component></text><line style="stroke:#A80036;stroke-width:1.5;" x1="143" x2="313" y1="317.1094" y2="317.1094"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="71" x="148" y="331.3198">+operation()</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="103" x="148" y="344.1245">+add(Component)</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="125" x="148" y="356.9292">+remove(Component)</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="77" x="148" y="369.7339">+getChild(int)</text><!--MD5=[0cff9a7be7be62801c7c77ee1751cfd5]
|
||||
class BomComp--><rect codeLine="44" fill="#FEFECE" height="128.4375" id="BomComp" style="stroke:#A80036;stroke-width:1.5;" width="214" x="518" y="50.8047"/><ellipse cx="549.9" cy="68.6094" fill="#A9DCDF" rx="9" ry="9" style="stroke:#A80036;stroke-width:1.0;"/><path d="M549.2125,65.5469 L548.4625,68.8281 L549.9625,68.8281 L549.2125,65.5469 Z M548.2438,64.0938 L550.1813,64.0938 L552.3531,72.1094 L550.7594,72.1094 L550.2594,70.125 L548.15,70.125 L547.6656,72.1094 L546.0719,72.1094 L548.2438,64.0938 Z " fill="#000000"/><text fill="#000000" font-family="Arial" font-size="11" font-style="italic" lengthAdjust="spacing" textLength="109" x="583.6" y="66.0151"><BomComponent></text><text fill="#000000" font-family="Arial" font-size="11" font-style="italic" lengthAdjust="spacing" textLength="144" x="566.1" y="78.8198">abstract (interfaz Python)</text><line style="stroke:#A80036;stroke-width:1.5;" x1="519" x2="731" y1="86.4141" y2="86.4141"/><line style="stroke:#A80036;stroke-width:1.5;" x1="519" x2="731" y1="94.4141" y2="94.4141"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="202" x="524" y="108.6245">+get_product_id() : product.product</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="125" x="524" y="121.4292">+get_quantity() : Float</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="132" x="524" y="134.2339">+get_uom() : uom.uom</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="104" x="524" y="147.0386">+get_cost() : Float</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="119" x="524" y="159.8433">+explode(level) : List</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="89" x="524" y="172.6479">+accept(visitor)</text><!--MD5=[8b71437d06f1f61dad5c939804e56ab0]
|
||||
class MrpBom--><rect codeLine="53" fill="#FEFECE" height="166.8516" id="MrpBom" style="stroke:#A80036;stroke-width:1.5;" width="285" x="371.5" y="238.8047"/><ellipse cx="446.75" cy="256.6094" fill="#ADD1B2" rx="9" ry="9" style="stroke:#A80036;stroke-width:1.0;"/><path d="M448.0625,260.375 Q447.6875,260.5781 447.2656,260.6719 Q446.8594,260.7656 446.3906,260.7656 Q444.7813,260.7656 443.9219,259.7031 Q443.0625,258.625 443.0625,256.6094 Q443.0625,254.5781 443.9219,253.5156 Q444.7813,252.4375 446.3906,252.4375 Q446.8594,252.4375 447.2656,252.5469 Q447.6875,252.6406 448.0625,252.8281 L448.0625,254.5938 Q447.6406,254.2188 447.25,254.0469 Q446.875,253.875 446.4688,253.875 Q445.6094,253.875 445.1563,254.5625 Q444.7188,255.25 444.7188,256.6094 Q444.7188,257.9688 445.1563,258.6563 Q445.6094,259.3438 446.4688,259.3438 Q446.875,259.3438 447.25,259.1719 Q447.6406,259 448.0625,258.6094 L448.0625,260.375 Z " fill="#000000"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="70" x="492.75" y="254.0151"><mrp.bom></text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="127" x="464.25" y="266.8198">(Producto Compuesto)</text><line style="stroke:#A80036;stroke-width:1.5;" x1="372.5" x2="655.5" y1="274.4141" y2="274.4141"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="122" x="377.5" y="288.6245">+_name = 'mrp.bom'</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="273" x="377.5" y="301.4292">+product_tmpl_id : Many2one(product.template)</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="235" x="377.5" y="314.2339">+product_id : Many2one(product.product)</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="240" x="377.5" y="327.0386">+bom_line_ids : One2many(mrp.bom.line)</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="114" x="377.5" y="339.8433">+product_qty : Float</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="230" x="377.5" y="352.6479">+product_uom_id : Many2one(uom.uom)</text><line style="stroke:#A80036;stroke-width:1.0;" x1="372.5" x2="655.5" y1="359.2422" y2="359.2422"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="157" x="377.5" y="373.4526">+explode(product, quantity)</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="120" x="377.5" y="386.2573">+_check_bom_cycle()</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="140" x="377.5" y="399.062">+action_compute_price()</text><!--MD5=[7f72ebc14164ccb3d18f581329da80c6]
|
||||
class MrpBomLine--><rect codeLine="66" fill="#FEFECE" height="154.0469" id="MrpBomLine" style="stroke:#A80036;stroke-width:1.5;" width="287" x="407.5" y="465.8047"/><ellipse cx="490.25" cy="483.6094" fill="#ADD1B2" rx="9" ry="9" style="stroke:#A80036;stroke-width:1.0;"/><path d="M491.5625,487.375 Q491.1875,487.5781 490.7656,487.6719 Q490.3594,487.7656 489.8906,487.7656 Q488.2813,487.7656 487.4219,486.7031 Q486.5625,485.625 486.5625,483.6094 Q486.5625,481.5781 487.4219,480.5156 Q488.2813,479.4375 489.8906,479.4375 Q490.3594,479.4375 490.7656,479.5469 Q491.1875,479.6406 491.5625,479.8281 L491.5625,481.5938 Q491.1406,481.2188 490.75,481.0469 Q490.375,480.875 489.9688,480.875 Q489.1094,480.875 488.6563,481.5625 Q488.2188,482.25 488.2188,483.6094 Q488.2188,484.9688 488.6563,485.6563 Q489.1094,486.3438 489.9688,486.3438 Q490.375,486.3438 490.75,486.1719 Q491.1406,486 491.5625,485.6094 L491.5625,487.375 Z " fill="#000000"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="94" x="517.75" y="481.0151"><mrp.bom.line></text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="114" x="507.75" y="493.8198">(Línea Componente)</text><line style="stroke:#A80036;stroke-width:1.5;" x1="408.5" x2="693.5" y1="501.4141" y2="501.4141"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="146" x="413.5" y="515.6245">+_name = 'mrp.bom.line'</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="235" x="413.5" y="528.4292">+product_id : Many2one(product.product)</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="179" x="413.5" y="541.2339">+bom_id : Many2one(mrp.bom)</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="275" x="413.5" y="554.0386">+child_bom_id : Many2one(mrp.bom, computed)</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="114" x="413.5" y="566.8433">+product_qty : Float</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="230" x="413.5" y="579.6479">+product_uom_id : Many2one(uom.uom)</text><line style="stroke:#A80036;stroke-width:1.0;" x1="408.5" x2="693.5" y1="586.2422" y2="586.2422"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="137" x="413.5" y="600.4526">+onchange_product_id()</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="103" x="413.5" y="613.2573">+_skip_bom_line()</text><!--MD5=[67b1e58ce3b6199df8341337c81d84ee]
|
||||
class ProductProduct--><rect codeLine="78" fill="#FEFECE" height="141.2422" id="ProductProduct" style="stroke:#A80036;stroke-width:1.5;" width="202" x="450" y="679.8047"/><ellipse cx="493.25" cy="697.6094" fill="#ADD1B2" rx="9" ry="9" style="stroke:#A80036;stroke-width:1.0;"/><path d="M494.5625,701.375 Q494.1875,701.5781 493.7656,701.6719 Q493.3594,701.7656 492.8906,701.7656 Q491.2813,701.7656 490.4219,700.7031 Q489.5625,699.625 489.5625,697.6094 Q489.5625,695.5781 490.4219,694.5156 Q491.2813,693.4375 492.8906,693.4375 Q493.3594,693.4375 493.7656,693.5469 Q494.1875,693.6406 494.5625,693.8281 L494.5625,695.5938 Q494.1406,695.2188 493.75,695.0469 Q493.375,694.875 492.9688,694.875 Q492.1094,694.875 491.6563,695.5625 Q491.2188,696.25 491.2188,697.6094 Q491.2188,698.9688 491.6563,699.6563 Q492.1094,700.3438 492.9688,700.3438 Q493.375,700.3438 493.75,700.1719 Q494.1406,700 494.5625,699.6094 L494.5625,701.375 Z " fill="#000000"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="108" x="510.75" y="695.0151"><product.product></text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="87" x="521.25" y="707.8198">(Producto Hoja)</text><line style="stroke:#A80036;stroke-width:1.5;" x1="451" x2="651" y1="715.4141" y2="715.4141"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="160" x="456" y="729.6245">+_name = 'product.product'</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="80" x="456" y="742.4292">+name : Char</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="99" x="456" y="755.2339">+list_price : Float</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="133" x="456" y="768.0386">+standard_price : Float</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="190" x="456" y="780.8433">+bom_ids : One2many(mrp.bom)</text><line style="stroke:#A80036;stroke-width:1.0;" x1="451" x2="651" y1="787.4375" y2="787.4375"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="65" x="456" y="801.6479">+get_cost()</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="108" x="456" y="814.4526">+explode_as_leaf()</text><!--MD5=[076294374d6fb851ab701d79716fe6cc]
|
||||
reverse link Comp to Leaf--><path codeLine="35" d="M139.35,114.8047 C139.35,114.8047 65,114.8047 65,114.8047 C65,114.8047 65,236.4347 65,293.4547 " fill="none" id="Comp-backto-Leaf" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="none" points="139.35,107.8047,159.35,114.8047,139.35,121.8047,139.35,107.8047" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[17ca7e596661b58ceb6974692aadc41c]
|
||||
reverse link Comp to CompClass--><path codeLine="36" d="M205.17,182.4047 C205.17,182.4047 205.17,267.9647 205.17,267.9647 " fill="none" id="Comp-backto-CompClass" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="none" points="198.17,182.4047,205.17,162.4047,212.17,182.4047,198.17,182.4047" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[fdb18a56b4dfddf104e114882e31efe6]
|
||||
reverse link CompClass to Comp--><path codeLine="37" d="M250.83,255.0547 C250.83,255.0547 250.83,162.3847 250.83,162.3847 " fill="none" id="CompClass-backto-Comp" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="250.83,268.0547,254.83,262.0547,250.83,256.0547,246.83,262.0547,250.83,268.0547" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="45" x="204.83" y="205.9251">children</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="7" x="246.5483" y="257.8474">1</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="6" x="247.8665" y="180.8444">*</text><!--MD5=[3c3a391dd4f2ef810a3f7bb66db373fc]
|
||||
reverse link BomComp to MrpBom--><path codeLine="89" d="M587.25,199.0347 C587.25,199.0347 587.25,238.5147 587.25,238.5147 " fill="none" id="BomComp-backto-MrpBom" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="none" points="580.25,199.0347,587.25,179.0347,594.25,199.0347,580.25,199.0347" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[182c4be38a755a9820124206408c6d0a]
|
||||
reverse link BomComp to MrpBomLine--><path codeLine="90" d="M675.5,198.8847 C675.5,198.8847 675.5,465.5947 675.5,465.5947 " fill="none" id="BomComp-backto-MrpBomLine" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="none" points="668.5,198.8847,675.5,178.8847,682.5,198.8847,668.5,198.8847" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[5c58149a8c67939004e649803647da73]
|
||||
reverse link BomComp to ProductProduct--><path codeLine="91" d="M713.25,198.9947 C713.25,198.9947 713.25,750.8047 713.25,750.8047 C713.25,750.8047 685.17,750.8047 652.37,750.8047 " fill="none" id="BomComp-backto-ProductProduct" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="none" points="706.25,198.9947,713.25,178.9947,720.25,198.9947,706.25,198.9947" style="stroke:#A80036;stroke-width:1.0;"/><!--MD5=[11c7495db121e69115b9bb1c429bf0fd]
|
||||
reverse link MrpBom to MrpBomLine--><path codeLine="93" d="M490.5,418.9847 C490.5,418.9847 490.5,465.7147 490.5,465.7147 " fill="none" id="MrpBom-backto-MrpBomLine" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="490.5,405.9847,486.5,411.9847,490.5,417.9847,494.5,411.9847,490.5,405.9847" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="74" x="415.5" y="439.5551">bom_line_ids</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="7" x="481.1797" y="423.943">1</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="6" x="477.9516" y="455.3956">*</text><!--MD5=[689214c5c1575da963ee69c30a8302c5]
|
||||
link MrpBomLine to MrpBom--><path codeLine="94" d="M573.5,465.6847 C573.5,465.6847 573.5,411.1447 573.5,411.1447 " fill="none" id="MrpBomLine-to-MrpBom" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="573.5,406.1447,569.5,415.1447,573.5,411.1447,577.5,415.1447,573.5,406.1447" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="141" x="574.5" y="435.6251">child_bom_id (computed)</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="6" x="569.5109" y="455.3625">*</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="22" x="555.5164" y="423.8345">0..1</text><!--MD5=[0fe7988514fdc306fbdd9233360e6a76]
|
||||
link MrpBomLine to ProductProduct--><path codeLine="95" d="M551,620.0747 C551,620.0747 551,674.4847 551,674.4847 " fill="none" id="MrpBomLine-to-ProductProduct" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="551,679.4847,555,670.4847,551,674.4847,547,670.4847,551,679.4847" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="59" x="491" y="644.4851">product_id</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="6" x="544.7234" y="637.9965">*</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="7" x="543.6172" y="669.3237">1</text><!--MD5=[167041e52da4663a658550e17dde73e5]
|
||||
reverse link ProductProduct to MrpBom--><path codeLine="96" d="M436.64,750.8047 C436.64,750.8047 389.5,750.8047 389.5,750.8047 C389.5,750.8047 389.5,530.6447 389.5,405.9447 " fill="none" id="ProductProduct-backto-MrpBom" style="stroke:#A80036;stroke-width:1.0;"/><polygon fill="#A80036" points="449.64,750.8047,443.64,746.8047,437.64,750.8047,443.64,754.8047,449.64,750.8047" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="48" x="340.5" y="599.1551">bom_ids</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="7" x="434.9393" y="748.6319">1</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="6" x="372.543" y="423.8995">*</text><rect fill="#DDDDDD" height="240.4844" rx="5" ry="5" style="stroke:#000000;stroke-width:1.0;" width="338" x="394" y="849.8047"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="131" x="400" y="865.0151">Proyecto: SAP-TFI-2026</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="107" x="400" y="877.8198">Agente: saptfi2026</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="232" x="400" y="890.6245">Patron: Composite (Gamma et al., 2003)</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="291" x="400" y="903.4292">Aplicado a: Lista de Materiales (BoM) en Odoo 19.0</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="305" x="400" y="916.2339">Motivacion: estructura jerarquica de productos donde</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="326" x="400" y="929.0386">un producto puede estar compuesto por otros productos</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="101" x="400" y="941.8433">(recursivamente).</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="0" x="404" y="954.6479"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="63" x="400" y="967.4526">Beneficios:</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="236" x="400" y="980.2573">- Cliente trata uniforme Leaf y Composite</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="232" x="400" y="993.062">- Composicion recursiva (BOM anidados)</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="266" x="400" y="1005.8667">- Operaciones polimorficas (explode, get_cost)</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="234" x="400" y="1018.6714">- Validacion de ciclos (_check_bom_cycle)</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="0" x="404" y="1031.4761"/><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="63" x="400" y="1044.2808">Trade-offs:</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="283" x="400" y="1057.0854">- Puede violar LSP si Leaf no soporta add/remove</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="169" x="400" y="1069.8901">- Dificil restringir tipo de hijos</text><text fill="#000000" font-family="Arial" font-size="11" lengthAdjust="spacing" textLength="223" x="400" y="1082.6948">- Ciclos deben validarse explicitamente</text><!--MD5=[5b0df9a591a5dbfa2cef1ffe3559a71c]
|
||||
@startuml D-PAT-COMPOSITE-001 — Patron Composite aplicado a Lista de Materiales (BoM)
|
||||
|
||||
title SAP-TFI-2026 — Patron Composite aplicado a Lista de Materiales (BoM) en Odoo 19.0
|
||||
|
||||
skinparam shadowing false
|
||||
skinparam handwritten false
|
||||
skinparam defaultFontName Arial
|
||||
skinparam defaultFontSize 11
|
||||
skinparam linetype ortho
|
||||
skinparam backgroundColor white
|
||||
skinparam classAttributeIconSize 0
|
||||
skinparam packageStyle rectangle
|
||||
|
||||
' ──────────────────── Patron Composite (GoF) ────────────────────
|
||||
|
||||
package "Patron Composite (GoF)" {
|
||||
abstract class "Component" as Comp {
|
||||
+operation()
|
||||
+add(Component)
|
||||
+remove(Component)
|
||||
+getChild(int)
|
||||
}
|
||||
|
||||
class "Leaf" as Leaf {
|
||||
+operation()
|
||||
}
|
||||
|
||||
class "Composite" as CompClass {
|
||||
-children: List<Component>
|
||||
+operation()
|
||||
+add(Component)
|
||||
+remove(Component)
|
||||
+getChild(int)
|
||||
}
|
||||
|
||||
Comp <|- - Leaf
|
||||
Comp <|- - CompClass
|
||||
CompClass "1" *- - "*" Comp : children
|
||||
}
|
||||
|
||||
' ──────────────────── Aplicacion al BoM de Odoo ────────────────────
|
||||
|
||||
package "Aplicacion: BoM (Bill of Materials) en Odoo 19.0" {
|
||||
|
||||
abstract class "<BomComponent>\nabstract (interfaz Python)" as BomComp {
|
||||
+get_product_id() : product.product
|
||||
+get_quantity() : Float
|
||||
+get_uom() : uom.uom
|
||||
+get_cost() : Float
|
||||
+explode(level) : List
|
||||
+accept(visitor)
|
||||
}
|
||||
|
||||
class "<mrp.bom>\n(Producto Compuesto)" as MrpBom {
|
||||
+_name = 'mrp.bom'
|
||||
+product_tmpl_id : Many2one(product.template)
|
||||
+product_id : Many2one(product.product)
|
||||
+bom_line_ids : One2many(mrp.bom.line)
|
||||
+product_qty : Float
|
||||
+product_uom_id : Many2one(uom.uom)
|
||||
- -
|
||||
+explode(product, quantity)
|
||||
+_check_bom_cycle()
|
||||
+action_compute_price()
|
||||
}
|
||||
|
||||
class "<mrp.bom.line>\n(Línea Componente)" as MrpBomLine {
|
||||
+_name = 'mrp.bom.line'
|
||||
+product_id : Many2one(product.product)
|
||||
+bom_id : Many2one(mrp.bom)
|
||||
+child_bom_id : Many2one(mrp.bom, computed)
|
||||
+product_qty : Float
|
||||
+product_uom_id : Many2one(uom.uom)
|
||||
- -
|
||||
+onchange_product_id()
|
||||
+_skip_bom_line()
|
||||
}
|
||||
|
||||
class "<product.product>\n(Producto Hoja)" as ProductProduct {
|
||||
+_name = 'product.product'
|
||||
+name : Char
|
||||
+list_price : Float
|
||||
+standard_price : Float
|
||||
+bom_ids : One2many(mrp.bom)
|
||||
- -
|
||||
+get_cost()
|
||||
+explode_as_leaf()
|
||||
}
|
||||
|
||||
BomComp <|- - MrpBom
|
||||
BomComp <|- - MrpBomLine
|
||||
BomComp <|- - ProductProduct
|
||||
|
||||
MrpBom "1" *- - "*" MrpBomLine : bom_line_ids
|
||||
MrpBomLine "*" - -> "0..1" MrpBom : child_bom_id (computed)
|
||||
MrpBomLine "*" - -> "1" ProductProduct : product_id
|
||||
ProductProduct "1" *- - "*" MrpBom : bom_ids
|
||||
}
|
||||
|
||||
legend right
|
||||
Proyecto: SAP-TFI-2026
|
||||
Agente: saptfi2026
|
||||
Patron: Composite (Gamma et al., 2003)
|
||||
Aplicado a: Lista de Materiales (BoM) en Odoo 19.0
|
||||
Motivacion: estructura jerarquica de productos donde
|
||||
un producto puede estar compuesto por otros productos
|
||||
(recursivamente).
|
||||
|
||||
Beneficios:
|
||||
- Cliente trata uniforme Leaf y Composite
|
||||
- Composicion recursiva (BOM anidados)
|
||||
- Operaciones polimorficas (explode, get_cost)
|
||||
- Validacion de ciclos (_check_bom_cycle)
|
||||
|
||||
Trade-offs:
|
||||
- Puede violar LSP si Leaf no soporta add/remove
|
||||
- Dificil restringir tipo de hijos
|
||||
- Ciclos deben validarse explicitamente
|
||||
endlegend
|
||||
|
||||
@enduml
|
||||
|
||||
@startuml D-PAT-COMPOSITE-001 — Patron Composite aplicado a Lista de Materiales (BoM)
|
||||
|
||||
title SAP-TFI-2026 — Patron Composite aplicado a Lista de Materiales (BoM) en Odoo 19.0
|
||||
|
||||
skinparam shadowing false
|
||||
skinparam handwritten false
|
||||
skinparam defaultFontName Arial
|
||||
skinparam defaultFontSize 11
|
||||
skinparam linetype ortho
|
||||
skinparam backgroundColor white
|
||||
skinparam classAttributeIconSize 0
|
||||
skinparam packageStyle rectangle
|
||||
|
||||
|
||||
package "Patron Composite (GoF)" {
|
||||
abstract class "Component" as Comp {
|
||||
+operation()
|
||||
+add(Component)
|
||||
+remove(Component)
|
||||
+getChild(int)
|
||||
}
|
||||
|
||||
class "Leaf" as Leaf {
|
||||
+operation()
|
||||
}
|
||||
|
||||
class "Composite" as CompClass {
|
||||
-children: List<Component>
|
||||
+operation()
|
||||
+add(Component)
|
||||
+remove(Component)
|
||||
+getChild(int)
|
||||
}
|
||||
|
||||
Comp <|- - Leaf
|
||||
Comp <|- - CompClass
|
||||
CompClass "1" *- - "*" Comp : children
|
||||
}
|
||||
|
||||
|
||||
package "Aplicacion: BoM (Bill of Materials) en Odoo 19.0" {
|
||||
|
||||
abstract class "<BomComponent>\nabstract (interfaz Python)" as BomComp {
|
||||
+get_product_id() : product.product
|
||||
+get_quantity() : Float
|
||||
+get_uom() : uom.uom
|
||||
+get_cost() : Float
|
||||
+explode(level) : List
|
||||
+accept(visitor)
|
||||
}
|
||||
|
||||
class "<mrp.bom>\n(Producto Compuesto)" as MrpBom {
|
||||
+_name = 'mrp.bom'
|
||||
+product_tmpl_id : Many2one(product.template)
|
||||
+product_id : Many2one(product.product)
|
||||
+bom_line_ids : One2many(mrp.bom.line)
|
||||
+product_qty : Float
|
||||
+product_uom_id : Many2one(uom.uom)
|
||||
- -
|
||||
+explode(product, quantity)
|
||||
+_check_bom_cycle()
|
||||
+action_compute_price()
|
||||
}
|
||||
|
||||
class "<mrp.bom.line>\n(Línea Componente)" as MrpBomLine {
|
||||
+_name = 'mrp.bom.line'
|
||||
+product_id : Many2one(product.product)
|
||||
+bom_id : Many2one(mrp.bom)
|
||||
+child_bom_id : Many2one(mrp.bom, computed)
|
||||
+product_qty : Float
|
||||
+product_uom_id : Many2one(uom.uom)
|
||||
- -
|
||||
+onchange_product_id()
|
||||
+_skip_bom_line()
|
||||
}
|
||||
|
||||
class "<product.product>\n(Producto Hoja)" as ProductProduct {
|
||||
+_name = 'product.product'
|
||||
+name : Char
|
||||
+list_price : Float
|
||||
+standard_price : Float
|
||||
+bom_ids : One2many(mrp.bom)
|
||||
- -
|
||||
+get_cost()
|
||||
+explode_as_leaf()
|
||||
}
|
||||
|
||||
BomComp <|- - MrpBom
|
||||
BomComp <|- - MrpBomLine
|
||||
BomComp <|- - ProductProduct
|
||||
|
||||
MrpBom "1" *- - "*" MrpBomLine : bom_line_ids
|
||||
MrpBomLine "*" - -> "0..1" MrpBom : child_bom_id (computed)
|
||||
MrpBomLine "*" - -> "1" ProductProduct : product_id
|
||||
ProductProduct "1" *- - "*" MrpBom : bom_ids
|
||||
}
|
||||
|
||||
legend right
|
||||
Proyecto: SAP-TFI-2026
|
||||
Agente: saptfi2026
|
||||
Patron: Composite (Gamma et al., 2003)
|
||||
Aplicado a: Lista de Materiales (BoM) en Odoo 19.0
|
||||
Motivacion: estructura jerarquica de productos donde
|
||||
un producto puede estar compuesto por otros productos
|
||||
(recursivamente).
|
||||
|
||||
Beneficios:
|
||||
- Cliente trata uniforme Leaf y Composite
|
||||
- Composicion recursiva (BOM anidados)
|
||||
- Operaciones polimorficas (explode, get_cost)
|
||||
- Validacion de ciclos (_check_bom_cycle)
|
||||
|
||||
Trade-offs:
|
||||
- Puede violar LSP si Leaf no soporta add/remove
|
||||
- Dificil restringir tipo de hijos
|
||||
- Ciclos deben validarse explicitamente
|
||||
endlegend
|
||||
|
||||
@enduml
|
||||
|
||||
PlantUML version 1.2021.16(Wed Dec 08 14:25:22 ART 2021)
|
||||
(GPL source distribution)
|
||||
Java Runtime: OpenJDK Runtime Environment
|
||||
JVM: OpenJDK 64-Bit Server VM
|
||||
Default Encoding: UTF-8
|
||||
Language: es
|
||||
Country: AR
|
||||
--></g></svg>
|
||||
|
After Width: | Height: | Size: 32 KiB |
Reference in New Issue
Block a user