Programowy import zamówień z pliku CSV do Magento


17

Przechodzimy ze starego, przestarzałego systemu punktów sprzedaży na używanie Magento 1.7 wyłącznie jako naszego punktu sprzedaży. Nie jest niespodzianką, że jednym z wyzwań, przed którymi stoimy, jest to, jak uzyskać prawie 20 lat nagrań ze starego systemu do Mage bez katastrofy.

Odkładając na bok wyzwanie nawet migracji danych klientów, problem, na którym koncentruję się w tym pytaniu, polega na tym, w jaki sposób zamierzam migrować historyczne dane zamówienia ze starego punktu sprzedaży do Mage. Nie jestem w 100% pewien dokładnych liczb, kiedy mówimy o wielu rekordach zamówień, ale powiedziałbym, że co najmniej milion.

Oto, co myślę, jeśli chodzi o podejście do tego:

  1. Dowiedz się dokładnie, jak należy sformatować dane, aby Magento dobrze się z nimi bawił. To, czy uda nam się to zrobić ze starego POS w formacie, który działa, jest wątpliwe, ale załóżmy przez chwilę, że idzie dobrze ...
  2. Utwórz plik .CSV z ładnie sformatowanymi danymi historycznymi
  3. Znajdź sposób na odczytanie tego .CSV do $orderobiektu Magento rząd po rzędzie -> save ()
  4. Zysk!

Mój problem polega na tym, że jestem trochę rozmyślny, jak podejść do punktu 2 i 3, idź. Mogę sformatować dane wychodzące ze starego POS, jednak potrzebuję, nawet jeśli jest to bardzo uciążliwe i dotyczy Perla, ale kiedy już mam plik .CSV (lub inny typ pliku, który faktycznie działałby dla tego procesu), jestem dość niejasny jak chciałbym wprowadzić go do obiektu zamówienia Magento.

Zrobiłem trochę googlingu i wymyśliłem przykłady ludzi używających obiektu zamówienia Mage'a do programowego importowania zamówień, ale mało dyskusji na temat tego, w jaki sposób łączą źródła danych inne niż przedni koszyk z tym obiektem. Studiowałem wersję obiektu zamówienia:

$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();

Oto moje szczegółowe pytania:

  1. Czy to wydaje się być nawet sensownie podejściem do tego problemu? A jeśli nie, jak myślisz, jak mógłbym podejść do tego problemu jak mniej idiota?
  2. Jeśli jest to sensowne podejście, czy potrzebuję innej .CSV dla każdego modelu wywołanego przez proces zamówienia? tj. Mage :: getModel („sprzedaż / zamówienie”), Mage :: getModel („sprzedaż / adres_ zamówienia”) itp.?
  3. Czy .CSV jest jeszcze właściwą drogą?
  4. Jak mam wprowadzić moje dane do tego obiektu, niezależnie od tego, czy dane te są zawarte w .CSV, czy co masz?
  5. Jak byś zajął się ograniczaniem kosztów ogólnych?

Nawet jeśli myślę o tym w całkowicie idiotyczny sposób, a ty mi to mówisz, naprawdę doceniam każdy wkład.

Dziekuję Dziekuję Dziękuję!


1
Nie ma to większego znaczenia dla twojej sprawy, ale spójrz na moje poprzednie pytanie i odpowiedź @BenMarks, która obejmuje parsowanie CSV w Magento i może być przydatna. magento.stackexchange.com/questions/232/…
pspahn

1
Możesz poszukać inspiracji: github.com/avstudnitz/AvS_FastSimpleImport Skupia się głównie na imporcie produktów i klientów, ale jest to szybki system importu. Mówiąc o milionach płyt, prawdopodobnie chcesz czegoś szybkiego. Użyłem tego wcześniej do importowania plików CSV produktu. Po prostu czytasz plik CSV i konwertujesz dane na tablice. Nie próbowałem jednak rozszerzać tego modułu, aby korzystał z zamówień. Więc nie mam pojęcia, jak to się ułoży. Powodzenia.
Vicky

Czy automatyzacja przepływu danych - importowanie importowanych zamówień byłoby złym pomysłem? Z tego, co przeczytałem, wydaje się, że jest to rozwiązanie dość powszechne.
sparecycle

Odpowiedzi:


9

Zaskoczony brak odpowiedzi tyloma głosami / widokami, więc ugryzę:

  1. Zależy to od starego systemu POS, masuj dane podczas importu.
  2. Zapoznaj się Varien_Ioszczególnie Varien_Io_File. Ponieważ najprawdopodobniej będziesz mieć do czynienia z tak dużą kolekcją danych, pamiętaj o używaniu strumieni takich jak StreamReadCsvi StreamWriteCsv. Więcej szczegółów na temat „strumienia” . Bez strumienia lub liniowego odczytu / zapisu możesz napotkać problemy z pamięcią w przypadku innych metod ładowania / zapisu.

Powyżej wspomniany jest przykład: (źródło 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
            );
        }
    }
}

Jeśli chodzi o importowanie zamówień, ten przykład pomógł najbardziej: (Źródło: 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());

Na tym przykładzie będziesz mieć duże zasoby, ponieważ Mage::getModel(...w pętlach foreach występują wezwania, co jest złą praktyką i najprawdopodobniej albo przekroczy limit czasu, albo zapełni pamięć dość szybko. Zwłaszcza jeśli masz to zapakowane w innym foreach / while.

To...

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

Powinien wyglądać następująco:

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

Nie próbowałbym powiązać wszystkich bitów danych CSV z obiektami Magento. Byłoby to szaleństwo i odrobina przesady, z punktami wejścia modelu zasobów $model->load(EntityId).

Pamiętaj również, jeśli próbujesz zaimportować ponad 100 000+ zamówień, byłbym zaniepokojony wydajnością po dużym imporcie, ponieważ jest to konieczne, aby utrzymać MySQL dostrojone do obsługi tak dużych woluminów, nie wspominając zbytnio, jeśli nie mylę się, że obiekty sprzedaży są nadal oparte na EAV, i nie działają dobrze przy dużym natężeniu ruchu. Istnieje powód, dla którego Magento Enterprise ma moduł Archiwum zamówień sprzedaży, aby wyciągać stare dane z „transakcyjnych” tabel zamówień sprzedaży, aby zapobiec rozdętym / nieaktualnym danym, które nie są potrzebne do przyjmowania zamówień.

Podsumowując: Chciałbym poruszyć wymagania i potrzeby firmy w zakresie przechowywania tak dużych danych, jeśli tylko raportowanie ma lepsze alternatywy dla tego zestawu niż Magento.



3

Biorąc pod uwagę wpływ tych historycznych zamówień na wydajność magento / mysql oraz fakt, że wszelkie linie produktów, które zostały wycofane, również będą musiały zostać zaimportowane, warto rozważyć przechowywanie historycznych zamówień wraz z klientem i produktami w czymś jak indeks elasticsearch i przeprowadzaj wyszukiwanie na żądanie. tzn. strona historii zamówień klientów.


1

Utworzenie oferty, a następnie utworzenie zamówienia zajmuje zbyt dużo czasu na ogromne dane importu zamówienia.

Tak więc zbadałem i znalazłem wniosek dotyczący ogromnych danych importu zamówień za pomocą zapytania mysql:

  1. Wstawiłem dane tylko do tabel zamówień.

  2. Aktualizacja increment_idrozpoznać Magento 1.x, że ostatnie zamówienie increment_idjest to

  3. To zapytanie nie tworzy żadnej oferty, faktury ani wysyłki:

    Zapytania 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;

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.