Mapeo de campos Shopify → SAP Business One
Referencia de cómo se arma cada documento SAP a partir del JSON de una orden
de Shopify. Los constructores viven en domain/*.py.
RUT del cliente (domain/business_partner.py)
| Prioridad |
Fuente |
Detalle |
| 1 |
order.note_attributes |
Se busca una entrada cuyo name contenga "rut" (sin distinguir mayúsculas). Se valida el value con el formato y el dígito verificador (módulo 11). |
| 2 (respaldo) |
Metafields del customer (Shopify) |
Solo si no apareció en note_attributes. Se recorre cada metafield buscando un value con formato de RUT válido. |
normalizar_rut: quita puntos/guión, mayúsculas (ej. "123456785") — uso
interno para validar.
formatear_rut: formato que usa SAP, "NNNNNNNN-D" (ej. "12345678-5")
— se usa en FederalTaxID, CardCode y el filtro de búsqueda en SAP.
Resolución de CardCode (resolver_card_code)
| Caso |
CardCode usado |
| Sin RUT válido |
sap.generic_card_code (config de la tienda) |
RUT válido, existe BusinessPartner con ese FederalTaxID |
El CardCode de ese BP |
| RUT válido, no existe |
Se crea un BP nuevo, CardCode = "C" + rut_sap |
| RUT válido, pero falla la creación del BP |
Cae a sap.generic_card_code |
En los tres primeros casos con RUT válido, rut_sap se guarda igual (para
FederalTaxID del Invoice), aunque termine usándose el CardCode genérico.
BusinessPartners (creación, domain/business_partner.py)
| Campo SAP |
Origen Shopify |
Nota |
CardCode |
— |
"C" + rut_sap |
CardName |
billing_address (nombre completo), si no customer |
fallback "Cliente Shopify" |
CardType |
— |
fijo "cCustomer" |
GroupCode |
— |
fijo 100 ("Clientes", mismo grupo que el genérico) |
FederalTaxID |
— |
rut_sap |
Phone1 |
billing_address.phone, si no customer.phone |
|
EmailAddress |
order.email, si no order.contact_email |
|
BPAddresses (dos entradas)
| Campo SAP |
Origen Shopify |
Nota |
AddressName |
— |
"BillTo" / "ShipTo" |
AddressType |
— |
bo_BillTo / bo_ShipTo |
Street |
address1 |
|
Block |
address2 |
|
City |
city |
|
ZipCode |
zip |
|
County |
province |
texto libre, no se traduce a código de región |
Country |
country_code |
solo si es "CL" |
TaxCode |
— |
fijo "IVA", solo en la dirección bo_ShipTo |
bo_BillTo sale de order.billing_address; bo_ShipTo de
order.shipping_address (si no hay, usa billing_address).
Invoices (factura de reserva, domain/invoice.py)
| Campo SAP |
Origen Shopify |
Nota |
CardCode |
— |
resuelto (ver arriba) |
CardName |
billing_address (nombre completo), si no customer |
fallback "Cliente Shopify" |
DocDate / DocDueDate |
created_at (solo fecha) |
mismo valor en ambos |
Series |
— |
sap.numbering_series.INVOICE (config tienda) |
DocType |
— |
fijo "dDocument_Items" |
DocCurrency |
— |
fijo "CLP" |
ReserveInvoice |
— |
fijo "tYES" (factura de reserva, no releva stock al crearse) |
NumAtCard |
order.name |
ej. "#7863", para ubicarla fácil |
FederalTaxID |
rut_sap |
solo si hay RUT válido; sobrescribe el del CardCode genérico |
U_ShopifyOrderId |
order.id |
UDF |
U_ShopifyStore |
— |
store_code de la config |
AddressExtension (prefijo BillTo/ShipTo)
| Campo SAP |
Origen Shopify |
Nota |
{p}Street |
address1 |
|
{p}Block |
address2 |
|
{p}Building |
phone |
reutilizado para guardar el teléfono |
{p}City |
city |
|
{p}ZipCode |
zip |
|
{p}County |
province |
|
{p}Country |
country_code |
solo si es "CL" |
BillTo* sale de billing_address, ShipTo* de shipping_address. SAP
calcula Address/Address2 (texto plano) solo a partir de estos campos —
no se arman a mano.
DocumentLines (una por line_item con sku)
| Campo SAP |
Origen Shopify |
Nota |
ItemCode |
sku |
|
Quantity |
quantity |
|
WarehouseCode |
— |
sap.default_warehouse_invoice (bodega virtual, fija por tienda) |
PriceAfterVAT |
price menos descuento, ver nota |
precio unitario, IVA incluido |
TaxCode |
— |
fijo "IVA" (hardcode, sin lista de precios) |
Cálculo de PriceAfterVAT: item.price es el precio unitario antes
de descuento. El descuento real está en discount_allocations (el campo
total_discount no siempre lo refleja). Fórmula:
IncomingPayments (domain/payment.py)
| Campo SAP |
Origen |
Nota |
CardCode |
invoice.CardCode |
mismo cliente que la Invoice |
CardName |
invoice.CardName |
|
DocType |
— |
fijo "rCustomer" |
DocDate |
invoice.DocDate |
misma fecha que la Invoice |
Series |
— |
sap.numbering_series.INCOMING_PAYMENT |
DocCurrency |
— |
fijo "CLP" |
PaymentCreditCards[] |
una línea por transacción efectiva con type = credit_card |
CreditCard = sap.payment_methods[gateway].credit_card; CreditCardNumber fijo "1234"; CardValidUntil fijo "2030-12-31"; VoucherNum = order.name (máx. 20); CreditSum = transaction.amount; CreditCur "CLP"; CreditType "cr_Regular"; NumOfPayments y SplitPayments del config; FirstPaymentDue = invoice.DocDate |
TransferAccount / TransferSum / TransferDate / TransferReference |
solo si hay transacciones con type = transfer (reversso) |
cuenta de sap.payment_methods[gateway].transfer_account; TransferSum = suma de esas transacciones; TransferReference = order.name |
Remarks |
gateways de las transacciones efectivas |
join con " + ", sin repetir. No se usa payment_gateway_names (lista también los intentos fallidos) |
PaymentInvoices[0].DocEntry |
invoice.DocEntry |
|
PaymentInvoices[0].InvoiceType |
— |
fijo "it_Invoice" |
PaymentInvoices[0].SumApplied |
total de la Invoice |
debe igualar la suma de las transacciones efectivas; si no, error y no se crea el pago. Ver docs/casos_especiales.md |
InventoryTransferRequests (domain/inventory_transfer.py)
Una por cada fulfillment de la orden (tienda o CD).
| Campo SAP |
Origen |
Nota |
CardCode / CardName |
invoice.CardCode / invoice.CardName |
|
Comments |
order.name |
|
DocDate / DueDate |
order.created_at (solo fecha) |
|
Series |
— |
sap.numbering_series.INVENTORY_TRANSFER_REQUEST |
FromWarehouse |
sap.locations[location_id].warehouse_code |
bodega real de ese location_id |
ToWarehouse |
— |
sap.default_warehouse_invoice (misma bodega virtual del Invoice) |
U_ShopifyOrderId / U_ShopifyStore |
order.id / store_code |
|
StockTransferLines (una por line_item del fulfillment)
| Campo SAP |
Origen |
Nota |
ItemCode |
sku del line_item del fulfillment |
no toda la orden, solo lo de ese fulfillment |
Quantity |
quantity |
|
FromWarehouseCode |
igual a FromWarehouse |
|
WarehouseCode |
igual a ToWarehouse |
|
location_id → {is_store, warehouse_code} sale de
config/stores/<tienda>.json → sap.locations.
StockTransfers (domain/stock_transfer.py, solo si is_store: true)
Se arma a partir de la ITR ya creada en SAP (se relee completa para
tener LineNum).
| Campo SAP |
Origen |
Nota |
CardCode / CardName / Comments |
copiados de la ITR |
|
DocDate |
itr.DocDate |
|
FromWarehouse / ToWarehouse |
copiados de la ITR |
mismo sentido que la solicitud |
Series |
— |
sap.numbering_series.STOCK_TRANSFER |
U_ShopifyOrderId / U_ShopifyStore |
copiados de la ITR |
|
StockTransferLines (una por línea de la ITR)
| Campo SAP |
Origen |
Nota |
ItemCode / Quantity / FromWarehouseCode / WarehouseCode |
copiados de la línea de la ITR |
|
BaseType |
— |
1250000001 (DocObjectCode de InventoryTransferRequests) |
BaseEntry |
itr.DocEntry |
|
BaseLine |
line.LineNum de la ITR |
|
DeliveryNotes (domain/delivery.py, solo si is_store: true)
Se arma a partir de la Invoice (base) y el StockTransfer ya creado
(para saber qué se transfirió realmente en este fulfillment).
| Campo SAP |
Origen |
Nota |
CardCode / CardName |
invoice.CardCode / invoice.CardName |
|
Comments |
invoice.NumAtCard |
|
DocDate |
invoice.DocDate |
|
Series |
— |
sap.numbering_series.DELIVERY |
U_ShopifyOrderId / U_ShopifyStore |
copiados de la Invoice |
|
DocumentLines (una por línea del StockTransfer, emparejada con la Invoice por ItemCode)
| Campo SAP |
Origen |
Nota |
ItemCode / Quantity |
línea del StockTransfer |
solo lo de este fulfillment, no toda la orden |
WarehouseCode |
línea de la Invoice con el mismo ItemCode |
|
BaseType |
— |
13 (ObjType clásico de Sales Invoice, oInvoices) |
BaseEntry |
invoice.DocEntry |
|
BaseLine |
LineNum de la línea de la Invoice |
|
Referencias cruzadas en la Invoice (agregar_referencia_documento)
Cada vez que se crea ITR, StockTransfer o Delivery, se hace PATCH Invoices agregando una entrada a DocumentReferences (sin pisar las que ya
existan):
| Documento creado |
RefObjType |
InventoryTransferRequests |
rot_InventoryTransferRequest |
StockTransfers |
rot_InventoryTransfer |
DeliveryNotes |
rot_DeliveryNotes |
Campos fijos / hardcode (pendientes de hacer configurables si hace falta)
| Campo |
Valor |
Dónde |
TaxCode (líneas de Invoice) |
"IVA" |
domain/invoice.py |
TaxCode (dirección ShipTo del BP) |
"IVA" |
domain/business_partner.py |
DocCurrency |
"CLP" |
Invoice, Payment |
| Datos de tarjeta (Payment) |
últimos dígitos "1234", vencimiento "2030-12-31" |
domain/payment.py (provisorios) |
GroupCode (BusinessPartner) |
100 |
domain/business_partner.py |
BaseType ITR→StockTransfer |
1250000001 |
domain/stock_transfer.py |
BaseType Invoice→Delivery |
13 |
domain/delivery.py |