Files
comercio-net/docs/parser_spec.md
T

195 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Especificación de Parseo — Órdenes de Compra CommerceNet Chile
## Formato del archivo
- XML con esquema EAN.UCC (GS1) basado en `As2Envelope.xsd`
- Codificación: ISO-8859-1
- Namespace: `http://www.uc-council.org/smp/schemas/eanucc`
## Estructura del XML
```
envelope
├── messageHeader
│ ├── creationDate
│ ├── userId
│ ├── messageIdentifier
│ ├── to/gln
│ ├── from/gln
│ └── representingParty/gln
└── body
└── transaction
└── command
└── documentCommand
├── documentCommandHeader (@type="ADD")
└── documentCommandOperand
└── order
├── @creationDate
├── @documentStatus
├── paymentTerms
│ ├── @type
│ ├── @eventType
│ └── netPayment/timePeriodDue (@type, value)
├── movementDate
├── movementDateType
├── typedEntityIdentification (@entityType="ORDER")
│ └── entityIdentification
│ ├── uniqueCreatorIdentification ← N° OC
│ └── contentOwner/gln
├── specialHandling
├── salesDepartamentNumber
├── orderType
├── promotionDealNumber
├── internalVendorNumber
├── buyer/gln
├── seller/gln
├── shipParty (@identificationType="SHIP_TO")/gln
├── shipFrom/name
├── currency
├── mainCarrierTransport
│ ├── mode
│ ├── means
│ └── carrierName
└── lineItem (@number)
├── netPrice/amount (@currencyISOcode)
├── PriceType
├── requestedQuantity (@UnitType)
├── containedUnits (@UnitType)
├── allowanceCharge (0..N)
│ ├── @allowanceOrChargeType ("ALLOWANCE" | "CHARGE")
│ └── monetaryAmountOrPercentage
│ ├── percentage
│ └── amount (@currencyISOcode)
├── itemIdentification
│ ├── gtin
│ ├── buyerItemNumber (opcional)
│ └── vendorItemNumber (opcional)
├── itemColor (opcional)
├── itemSize (opcional)
├── itemDescription (@language)/text
└── totalAmount/amount (@currencyISOcode)
```
## Reglas generales
- Todos los valores provienen **exclusivamente** del contenido XML
- El nombre del archivo es solo referencial
- No inventar campos que no existan en el XML
- No recortar ni modificar valores
## Mapeo Cabecera
| Columna | Ruta XPath / Campo | Notas |
|---|---|---|
| Emisor | `envelope/messageHeader/from/gln` | |
| Receptor | `envelope/messageHeader/to/gln` | |
| N° Orden de Compra | `envelope/body/transaction/command/documentCommand/documentCommandOperand/order/typedEntityIdentification[@entityType='ORDER']/entityIdentification/uniqueCreatorIdentification` | Valor completo, sin recortes |
| Fecha generación mensaje | `envelope/body/transaction/command/documentCommand/documentCommandOperand/order/@creationDate` | Atributo creationDate del elemento order |
| Fecha de embarque | `envelope/body/transaction/command/documentCommand/documentCommandOperand/order/movementDate` | movementDate con movementDateType REQUESTED_DELIVERY |
| Fecha de cancelación | — | No existe en el XML, se deja vacío |
| Condiciones de pago | `paymentTerms/netPayment/timePeriodDue` | Formato: "NET {días} días desde fecha de factura" |
| Lugar de entrega | `shipParty[@identificationType='SHIP_TO']/gln` | |
| Dpto. ventas | `salesDepartamentNumber` | |
| Tipo OC | `orderType` | |
| Promoción | `promotionDealNumber` | |
| N° Proveedor | `internalVendorNumber` | |
| Observaciones | `specialHandling` | |
## Mapeo Detalle (por línea)
Orden de columnas:
| # | Columna | Ruta XPath | Notas |
|---|---|---|---|
| 1 | Línea | `lineItem/@number` | |
| 2 | Cód. UPC (GTIN) | `lineItem/itemIdentification/gtin` | |
| 3 | Item (buyer) | `lineItem/itemIdentification/buyerItemNumber` | |
| 4 | Cód. Prov. | `lineItem/itemIdentification/vendorItemNumber` | |
| 5 | Color/Talla/UM | `itemColor` + `itemSize` | Concatenar como "Color / Talla" según lo que traiga cada producto |
| 6 | Descripción | `itemDescription[@language='SP']/text` | Primer elemento |
| 7 | Precio Unit. | `netPrice/amount` | Moneda del atributo @currencyISOcode |
| 8 | Empaques | `requestedQuantity` | Cantidad solicitada en unidades de empaque (CSC = cajas) |
| 9 | Unid/Empaque | `containedUnits` | Unidades contenidas por empaque (SIN) |
| 10 | Cantidad (unid) | — | **Derivado**: Empaques × Unid/Empaque |
| 11 | Importe | `totalAmount/amount` | Moneda del atributo @currencyISOcode |
### Notas sobre UM
- `requestedQuantity/@UnitType` = CSC o CS (Case) → Empaques
- `containedUnits/@UnitType` = SIN (Unit) → Unid/Empaque
- Los campos `itemColor` e `itemSize` son **opcionales** según el emisor. Si no existen, la columna "Color/Talla/UM" se deja vacía.
### Algoritmo de Descuentos (allowanceCharge)
Cada línea puede tener 0 o más bloques `allowanceCharge`. Se procesan según su tipo:
```
base_total = netPrice × requestedQuantity
para cada allowanceCharge:
si percentage > 0:
descuento = round(base_total × percentage / 100) ← round a entero, .5 hacia arriba
si no:
descuento = round(amount) ← monto fijo
base_total = base_total - descuento
totalAmount (calculado) = base_total
precio_efectivo = round(totalAmount / requestedQuantity)
```
**Reglas:**
- Los descuentos se aplican **secuencialmente** sobre el saldo restante (no todos sobre el original)
- Si `percentage > 0`, se usa el porcentaje sobre el total actual; si no, se usa el `amount` como monto fijo
- El resultado final debe coincidir con `lineItem/totalAmount/amount`
- Si hay múltiples allowance, se encadenan: primero el primero sobre el total original, luego el siguiente sobre el resultado anterior
- `precio_efectivo` se calcula como el total con descuento dividido por la cantidad solicitada
**Ejemplos validados contra archivos reales:**
| Lín | Precio | CS | Base | Allowances | Cálculo | totalAmount XML |
|---|---|---|---|---|---|---|
| 1 | 32.230 | 2 | 64.460 | 25% → round(16.115)=16.115; 30% → round(48.345×30%)=14.504 | 64.460−16.115−14.504 = **33.841** | 33.841 ✅ |
| 2 | 35.939 | 38 | 1.365.682 | 25% → round(341.420,5)=341.421; 15% → round(1.024.261×15%)=153.639 | 1.365.682−341.421−153.639 = **870.622** | 870.622 ✅ |
| 9 | 39.097 | 1 | 39.097 | 25% → round(9.774,25)=9.774 | 39.097−9.774 = **29.323** | 29.323 ✅ |
| 10 | 39.097 | 2 | 78.194 | 25% → round(19.548,5)=19.549 | 78.194−19.549 = **58.645** | 58.645 ✅ |
| 20 | 170.000 | 4 | 680.000 | 25% → 170.000; 20% → round(510.000×20%)=102.000 | 680.000−170.000−102.000 = **408.000** | 408.000 ✅ |
## Mapeo Totales Finales
| Columna | Ruta XPath / Derivación | Notas |
|---|---|---|
| Importe total | Suma de `lineItem/totalAmount/amount` | O también `order/totalAmount` si existiera |
| Etapa de transporte | `mainCarrierTransport/mode` | |
| Quien transporta | `mainCarrierTransport/carrierName` | |
| Divisa de referencia | `currency` | |
| Condiciones de entrega | — | No existe en el XML |
## Diferencias entre emisores
| Elemento | Walmart (925485K200) | Otros emisores |
|---|---|---|
| Namespace | Sin prefijo (`xmlns=`) | Con prefijo `eanucc:` |
| `requestedQuantity/@UnitType` | CSC | CS |
| `itemColor`, `itemSize` | Presente | Ausente |
| `buyerItemNumber`, `vendorItemNumber` | Presente | Ausente |
| `salesDepartamentNumber`, `orderType` | Presente | Ausente |
| `promotionDealNumber` | POS REPLEN | Ausente |
| `internalVendorNumber` | Presente | Ausente |
| `specialHandling` | NO PRETICKET | Ausente |
| `mainCarrierTransport`, `currency` | Presente | Ausente |
| `allowanceCharge` | Ausente | Presente (con descuentos reales o en 0) |
## Diferencia entre tipos de OC
- `orderType=20`: Tipo estándar
- `orderType=33`: Tipo distinto (ej. reposición directa)
- Ambos con `promotionDealNumber="POS REPLEN"`
## Manejo de Namespace
Los archivos pueden venir con o sin prefijo:
- **Con prefijo**: `<eanucc:envelope>`, `<eanucc:order>` — usar el namespace `eanucc:` para las consultas XPath
- **Sin prefijo**: `<envelope>`, `<order>` — namespace por default
Solución recomendada: registrar ambos namespaces y usar `*` o registrar el namespace URI `http://www.uc-council.org/smp/schemas/eanucc` con un alias en el parser.