Importar pedidos desde un CSV a Magento mediante programación


17

Estamos cambiando de un sistema de punto de venta antiguo y anticuado a usar Magento 1.7 como nuestro punto de venta exclusivo. Como era de esperar, uno de los desafíos que enfrentamos es cómo obtener casi 20 años de registros del antiguo sistema a Mage sin catástrofe.

Dejando a un lado el desafío de incluso migrar los registros de clientes, el problema en el que me estoy centrando en esta pregunta es cómo voy a migrar los datos de pedidos históricos del antiguo TPV a Mage. No estoy 100% seguro de los números exactos cuando hablamos de muchos registros de pedidos, pero diría que al menos un millón.

Esto es lo que estoy pensando en términos de cómo abordar esto:

  1. Descubre exactamente cómo se deben formatear los datos para que Magento juegue bien con ellos. Es cuestionable si podemos sacarlo del antiguo TPV en un formato que funcione, pero supongamos por un momento que esto va bien ...
  2. Cree un archivo .CSV con datos históricos bien formateados
  3. Encuentre una manera de leer ese .CSV en el $orderobjeto de Magento fila por fila -> save ()
  4. ¡Lucro!

Mi problema es que estoy un poco confuso sobre cómo abordar los puntos 2 y 3, imagínense. Puedo formatear los datos que salen del antiguo TPV, sin embargo, lo necesito, incluso si es muy engorroso e involucra a Perl, pero una vez que tengo el archivo .CSV (o el tipo de archivo que realmente funcione para este proceso), no tengo muy claro cómo lo alimentaría al objeto de pedido de Magento

Busqué en Google y encontré ejemplos de personas que usan el objeto de pedido de Mage para importar pedidos mediante programación, pero poca discusión sobre cómo están conectando fuentes de datos distintas del carro frontal a dicho objeto. He estado estudiando una versión del objeto de pedido:

$id=1; // get Customer Id
$customer = Mage::getModel('customer/customer')->load($id);

$transaction = Mage::getModel('core/resource_transaction');
$storeId = $customer->getStoreId();
$reservedOrderId = Mage::getSingleton('eav/config')->getEntityType('order')->fetchNewIncrementId($storeId);

$order = Mage::getModel('sales/order')
  ->setIncrementId($reservedOrderId)
  ->setStoreId($storeId)
  ->setQuoteId(0)
  ->setGlobal_currency_code('USD')
  ->setBase_currency_code('USD')
  ->setStore_currency_code('USD')
  ->setOrder_currency_code('USD');

// set Customer data
$order->setCustomer_email($customer->getEmail())
  ->setCustomerFirstname($customer->getFirstname())
  ->setCustomerLastname($customer->getLastname())
  ->setCustomerGroupId($customer->getGroupId())
  ->setCustomer_is_guest(0)
  ->setCustomer($customer);

// set Billing Address
$billing = $customer->getDefaultBillingAddress();
$billingAddress = Mage::getModel('sales/order_address')
  ->setStoreId($storeId)
  ->setAddressType(Mage_Sales_Model_Quote_Address::TYPE_BILLING)
  ->setCustomerId($customer->getId())
  ->setCustomerAddressId($customer->getDefaultBilling())
  ->setCustomer_address_id($billing->getEntityId())
  ->setPrefix($billing->getPrefix())
  ->setFirstname($billing->getFirstname())
  ->setMiddlename($billing->getMiddlename())
  ->setLastname($billing->getLastname())
  ->setSuffix($billing->getSuffix())
  ->setCompany($billing->getCompany())
  ->setStreet($billing->getStreet())
  ->setCity($billing->getCity())
  ->setCountry_id($billing->getCountryId())
  ->setRegion($billing->getRegion())
  ->setRegion_id($billing->getRegionId())
  ->setPostcode($billing->getPostcode())
  ->setTelephone($billing->getTelephone())
  ->setFax($billing->getFax());
$order->setBillingAddress($billingAddress);

$shipping = $customer->getDefaultShippingAddress();
$shippingAddress = Mage::getModel('sales/order_address')
  ->setStoreId($storeId)
  ->setAddressType(Mage_Sales_Model_Quote_Address::TYPE_SHIPPING)
  ->setCustomerId($customer->getId())
  ->setCustomerAddressId($customer->getDefaultShipping())
  ->setCustomer_address_id($shipping->getEntityId())
  ->setPrefix($shipping->getPrefix())
  ->setFirstname($shipping->getFirstname())
  ->setMiddlename($shipping->getMiddlename())
  ->setLastname($shipping->getLastname())
  ->setSuffix($shipping->getSuffix())
  ->setCompany($shipping->getCompany())
  ->setStreet($shipping->getStreet())
  ->setCity($shipping->getCity())
  ->setCountry_id($shipping->getCountryId())
  ->setRegion($shipping->getRegion())
  ->setRegion_id($shipping->getRegionId())
  ->setPostcode($shipping->getPostcode())
  ->setTelephone($shipping->getTelephone())
->setFax($shipping->getFax());

$order->setShippingAddress($shippingAddress)
  ->setShipping_method('flatrate_flatrate')
  ->setShippingDescription($this->getCarrierName('flatrate'));

$orderPayment = Mage::getModel('sales/order_payment')
  ->setStoreId($storeId)
  ->setCustomerPaymentId(0)
  ->setMethod('purchaseorder')
  ->setPo_number(' - ');
$order->setPayment($orderPayment);

// let say, we have 2 products
$subTotal = 0;
  $products = array(
  '1001' => array(
  'qty' => 1
  ),
  '1002' ->array(
  'qty' => 3
  ),
);
foreach ($products as $productId=>$product) {
  $_product = Mage::getModel('catalog/product')->load($productId);
  $rowTotal = $_product->getPrice() * $product['qty'];
  $orderItem = Mage::getModel('sales/order_item')
    ->setStoreId($storeId)
    ->setQuoteItemId(0)
    ->setQuoteParentItemId(NULL)
    ->setProductId($productId)
    ->setProductType($_product->getTypeId())
    ->setQtyBackordered(NULL)
    ->setTotalQtyOrdered($product['rqty'])
    ->setQtyOrdered($product['qty'])
    ->setName($_product->getName())
    ->setSku($_product->getSku())
    ->setPrice($_product->getPrice())
    ->setBasePrice($_product->getPrice())
    ->setOriginalPrice($_product->getPrice())
    ->setRowTotal($rowTotal)
    ->setBaseRowTotal($rowTotal);

  $subTotal += $rowTotal;
  $order->addItem($orderItem);
}

$order->setSubtotal($subTotal)
  ->setBaseSubtotal($subTotal)
  ->setGrandTotal($subTotal)
  ->setBaseGrandTotal($subTotal);

$transaction->addObject($order);
$transaction->addCommitCallback(array($order, 'place'));
$transaction->addCommitCallback(array($order, 'save'));
$transaction->save();

Así que aquí están mis preguntas específicas:

  1. ¿Parece esto un enfoque incluso remotamente sensorial para este problema? Y si no, ¿cómo crees que podría abordar este tema como un idiota?
  2. Si este es un enfoque sensorial, ¿necesito un .CSV diferente para cada modelo invocado por el proceso de pedido? es decir, Mage :: getModel ('ventas / pedido'), Mage :: getModel ('ventas / pedido_dirección'), etc.
  3. ¿Es un .CSV incluso el camino a seguir?
  4. ¿Cómo ingresaría mis datos a este objeto, si esos datos están contenidos en un .CSV o qué tiene usted?
  5. ¿Cómo harías para limitar los gastos generales?

Incluso si estoy pensando en esto de una manera totalmente idiota y me lo dices, realmente agradezco cualquier aporte.

¡Gracias, gracias, gracias!


1
Realmente no es significativo para su caso, pero eche un vistazo a una pregunta anterior mía y a la respuesta de @BenMarks, que implica analizar CSV en Magento y podría ser útil. magento.stackexchange.com/questions/232/…
pspahn

1
Es posible que desee ver esto en busca de inspiración: github.com/avstudnitz/AvS_FastSimpleImport Se centra principalmente en importar productos y clientes, pero es un sistema de importación rápido. Como estás hablando de millones de discos, probablemente quieras algo rápido. He usado esto antes para importar archivos CSV de productos. Acabas de leer el archivo CSV y convertir los datos en matrices. Sin embargo, no he tratado de extender este módulo para usar órdenes. Así que no tengo idea de cómo funcionará eso. Buena suerte.
Vicky

Entonces, ¿sería una mala idea automatizar Dataflow - Importaciones para importar pedidos? Por lo que he leído, parece ser una solución bastante común.
reciclar

Respuestas:


9

No me sorprendió ninguna respuesta con tantos votos / opiniones, así que muerdo:

  1. Esto dependería del antiguo sistema POS, masajear los datos durante la importación.
  2. Familiarícese con Varien_Io, particularmente Varien_Io_File. Dado que lo más probable es que se trate de una recopilación de datos tan grande, tenga en cuenta el uso de transmisiones como StreamReadCsvy StreamWriteCsv. Más detalles sobre un "flujo" . Sin una secuencia o lectura / escritura lineal, puede encontrar problemas de memoria con otros métodos de carga / escritura.

Con lo anterior dicho aquí es un ejemplo: (fuente Atwix.com )

/**
 * Generates CSV file with product's list according to the collection in the $this->_list
 * @return array
 */
public function generateMlnList()
{
    if (!is_null($this->_list)) {
        $items = $this->_list->getItems();
        if (count($items) > 0) {

            $io = new Varien_Io_File();
            $path = Mage::getBaseDir('var') . DS . 'export' . DS;
            $name = md5(microtime());
            $file = $path . DS . $name . '.csv';
            $io->setAllowCreateFolders(true);
            $io->open(array('path' => $path));
            $io->streamOpen($file, 'w+');
            $io->streamLock(true);

            $io->streamWriteCsv($this->_getCsvHeaders($items));
            foreach ($items as $product) {
                $io->streamWriteCsv($product->getData());
            }

            return array(
                'type'  => 'filename',
                'value' => $file,
                'rm'    => true // can delete file after use
            );
        }
    }
}

En cuanto a la importación de pedidos, este ejemplo ha ayudado más: (Fuente: pastebin )

<?php

require_once 'app/Mage.php';

Mage::app();

$quote = Mage::getModel('sales/quote')
    ->setStoreId(Mage::app()->getStore('default')->getId());

if ('do customer orders') {
    // for customer orders:
    $customer = Mage::getModel('customer/customer')
        ->setWebsiteId(1)
        ->loadByEmail('customer@example.com');
    $quote->assignCustomer($customer);
} else {
    // for guesr orders only:
    $quote->setCustomerEmail('customer@example.com');
}

// add product(s)
$product = Mage::getModel('catalog/product')->load(8);
$buyInfo = array(
    'qty' => 1,
    // custom option id => value id
    // or
    // configurable attribute id => value id
);
$quote->addProduct($product, new Varien_Object($buyInfo));

$addressData = array(
    'firstname' => 'Test',
    'lastname' => 'Test',
    'street' => 'Sample Street 10',
    'city' => 'Somewhere',
    'postcode' => '123456',
    'telephone' => '123456',
    'country_id' => 'US',
    'region_id' => 12, // id from directory_country_region table
);

$billingAddress = $quote->getBillingAddress()->addData($addressData);
$shippingAddress = $quote->getShippingAddress()->addData($addressData);

$shippingAddress->setCollectShippingRates(true)->collectShippingRates()
        ->setShippingMethod('flatrate_flatrate')
        ->setPaymentMethod('checkmo');

$quote->getPayment()->importData(array('method' => 'checkmo'));

$quote->collectTotals()->save();

$service = Mage::getModel('sales/service_quote', $quote);
$service->submitAll();
$order = $service->getOrder();

printf("Created order %s\n", $order->getIncrementId());

Con el ejemplo que tiene ahora tendrá muchos recursos, ya que hay Mage::getModel(...llamadas en los bucles foreach que es , tendrá muchos mala práctica , y muy probablemente agote el tiempo de espera o llene la memoria con bastante rapidez. Especialmente si tienes esto envuelto en otro foreach / while.

Esta...

foreach ($products as $productId=>$product) {
  $_product = Mage::getModel('catalog/product')->load($productId);

Debería verse así:

$_product = Mage::getModel('catalog/product');
foreach ($products as $productId=>$product) {
  $_product->load($productId);

No intentaría intentar relacionar todos los bits de datos CSV con los objetos de Magento. Sería una locura y un poco exagerado, seguir con los puntos de entrada del modelo de recursos de$model->load(EntityId) .

También tenga en cuenta si está intentando importar más de 100k + pedidos, me preocuparía el rendimiento después de las grandes importaciones, ya que es necesario mantener MySQL sintonizado para manejar volúmenes tan grandes, sin mencionar si no me equivoco, los objetos de ventas todavía están basados ​​en EAV, y no funcionan bien bajo alto volumen / tráfico. Hay una razón por la cual Magento Enterprise tiene un módulo de Archivo de pedidos de ventas para extraer datos antiguos de las tablas de pedidos de ventas "transaccionales" para evitar datos hinchados / obsoletos que no son necesarios para tomar pedidos.

Para concluir: plantearía los requisitos y las necesidades de la empresa para almacenar datos tan grandes, si solo informa que hay mejores alternativas para combinar esto que Magento.



3

Pensando en el impacto que estas órdenes históricas tendrían en el rendimiento de magento / mysql más el hecho de que cualquier línea de productos que haya sido descontinuada también debería importarse, entonces podría valer la pena considerar almacenar las órdenes históricas junto con el cliente y los productos en algo como un índice de búsqueda elástica y realizar una búsqueda bajo demanda. es decir, la página del historial de pedidos del cliente.


1

Crear una cotización y luego crear una orden lleva demasiado tiempo para la gran cantidad de datos de importación de la orden.

Entonces, investigué y encontré la conclusión de datos de importación de pedidos enormes con la consulta mysql:

  1. Inserté los datos en solo tablas de pedidos.

  2. Actualice increment_idpara reconocer magento 1.x, ese último orden increment_ides este

  3. Esta consulta no está creando ninguna cotización, factura y envío:

    Consultas SQL: -

    1. INSERT INTO `sales_flat_order` (state, status, shipping_description, store_id, customer_id, base_discount_invoiced, base_grand_total, base_shipping_amount, base_shipping_invoiced, base_subtotal, base_subtotal_invoiced, base_tax_amount, base_tax_invoiced, base_total_invoiced, base_total_invoiced_cost, base_total_paid, discount_invoiced, grand_total, shipping_amount, shipping_invoiced, subtotal, subtotal_invoiced, tax_amount, tax_invoiced, total_invoiced, total_paid, customer_group_id, increment_id, base_currency_code, global_currency_code, customer_email, customer_firstname, customer_lastname, customer_middlename, order_currency_code, shipping_method, store_currency_code, store_name, created_at, updated_at, total_item_count, hidden_tax_invoiced, base_hidden_tax_invoiced, is_valid) VALUES ("complete", "complete", "Flat Rate - Fixed", 1, 38322,0,225.7,0,0,214.95,214.95,10.75,10.75,225.7, 0,225.7, 0,225.7,0,0,214.95,214.95,10.75,10.75,225.7,225.7, 1,100026111,"CAD","CAD","abc@gmail.com","abc","abc","", "CAD", "flatrate_flatrate", "CAD", "Main Website\nMain Website Store\nOnline Catalog","2012-01-17 00:00:00","2012-01-17 00:00:00",5,0,0,0);

    2. INSERT INTO `sales_flat_order_grid` (entity_id, status, shipping_description, shipping_method, store_id, customer_id, customer_email, total_qty_ordered, base_grand_total, base_total_paid, grand_total, total_paid, increment_id, base_currency_code, order_currency_code, store_name, created_at, updated_at, payment_validated, billing_name, shipping_name) VALUES (5, "complete", "Flat Rate - Fixed", "flatrate_flatrate", 1, 38322,"abc@gmail.com",5,225.7,225.7,225.7,225.7,100026111,"CAD", "CAD", "Main Website\nMain Website Store\nOnline Catalog","2012-01-17 00:00:00","2012-01-17 00:00:00",1,"abc abc","abc abc");

    3. INSERT INTO `sales_flat_order_address` (parent_id, region_id, customer_id, email, region, postcode, lastname, street, city, telephone, country_id, firstname, address_type, middlename, nick_name) VALUES (5,68,38322,"alicjakeller@gmail.com","Manitoba","R3W 1G9","abc","1607 Concordia Ave E","Winnipeg","204 667-5540","CA","abc","billing","","")

    4. INSERT INTO `sales_flat_order_address` (parent_id, region_id, customer_id, email, region, postcode, lastname, street, city, telephone, country_id, firstname, address_type, middlename, nick_name) VALUES (5,68,38322,"alicjakeller@gmail.com","Manitoba","R3W 1G9","abc","1607 Concordia Ave E","Winnipeg","204 667-5540","CA","abc","shipping","","");

    5. INSERT INTO `sales_flat_order_item` (order_id, store_id, created_at, updated_at, product_id, product_type, sku, name, qty_ordered, price, base_price, original_price, base_original_price, row_total, base_row_total, price_incl_tax, base_price_incl_tax, row_total_incl_tax, base_row_total_incl_tax) VALUES (5,1,"2012-01-17 00:00:00","2012-01-17 00:00:00",4134,"simple","MET2240","ULTRA FLORA IB - 30 CAPS",4,44.99,44.99,44.99,44.99,179.96,179.96,44.99,44.99,179.96,179.96);

    6. INSERT INTO `sales_flat_order_item` (order_id, store_id, created_at, updated_at, product_id, product_type, sku, name, qty_ordered, price, base_price, original_price, base_original_price, row_total, base_row_total, price_incl_tax, base_price_incl_tax, row_total_incl_tax, base_row_total_incl_tax) VALUES (5,1,"2012-01-17 00:00:00","2012-01-17 00:00:00",3198,"simple","WS1600","THYROSENSE - 180 VCAPS + 60 VCAPS FREE",1,34.99,34.99,34.99,34.99,34.99,34.99,34.99,34.99,34.99,34.99);

    7. INSERT INTO `sales_flat_order_payment` (parent_id, base_shipping_amount, shipping_amount, base_amount_paid, amount_paid, base_amount_ordered, amount_ordered, method) VALUES (5,0,0,225.7,225.7,225.7,225.7, "cashondelivery");

    8. UPDATE `eav_entity_store` SET increment_last_id = 100026111 WHERE `entity_type_id` = 5 AND `store_id` = 1;

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.