3 require_once 'Pman/Roo.php';
5 class Pman_Xtuple_Import_MagentoOld extends Pman_Roo
10 if (HTML_FlexyFramework::get()->cli) {
11 $this->authUser = DB_DataObject::Factory('Person');
12 $this->authUser->get('email','brian@bloomandgrowdirect.com');
15 return parent::getAuth();
22 ini_set('memory_limit', '1024M');
23 $this->sessionState(0); // turn off session..
24 //$this->transObj = DB_DataObject::Factory('coitem');
26 // $this->transObj->query('BEGIN');
28 PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($this, 'onPearError'));
30 $this->timer = microtime(true);
32 require_once 'File/Convert.php';
34 $this->debugLog('reading /tmp/magento.csv');
35 $fc = new File_Convert('/tmp/magento.csv', 'text/csv');
36 $content = $fc->convert('text/csv');
37 $this->debugLog('running import CSV');
38 $this->importCsv($content, '');
43 function debugLog($str)
45 if (!HTML_FlexyFramework::get()->cli) {
48 static $start = false;
51 $start = microtime(true);
53 $timed = microtime(true) - $start;
56 echo number_format($timed/60 ,2, '.',','). 'm MEM:' . number_format(memory_get_usage() /1000000,0, '.',','). 'M : '. $str . "\n";
63 ini_set('memory_limit', '512M');
65 $this->timer = microtime(true);
67 $this->sessionState(0); // turn off session..
68 //$this->transObj = DB_DataObject::Factory('coitem');
70 // $this->transObj->query('BEGIN');
72 PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, array($this, 'onPearError'));
74 $img = DB_DataObject::Factory('images');
77 'ontable' => 'ipshead'
79 $img->onUpload(false);
81 require_once 'File/Convert.php';
82 $fc = new File_Convert($img->getStoreName(), $img->mimetype );
83 $csv = $fc->convert('text/csv');
84 $this->importCsv($csv);
87 function importCsv($content, $header = '')
89 ini_set("auto_detect_line_endings", true);
93 'order number', 'order date', 'customer name', 'email', 'billing name', 'address',
94 'city', 'state', 'postalcode', 'country', 'phone', 'ship type', 'unknown1', 'ship note',
95 'signature required', 'weight', 'subtotal', 'freight', 'total', 'tax', 'item name', 'item description',
96 'quantity', 'item total', 'discount', 'payment type', 'unknown2', 'unknown3', 'discount description'
101 $fh = fopen($header, 'r');
103 $this->jerr("invalid header file");
105 while(false !== ($n = fgetcsv($fh,10000, ',', '"'))) {
107 $col[] = strtoupper(trim($h));
111 $this->debugLog('reading file');
113 $fh = fopen($content, 'r');
115 $this->jerr("invalid content file");
121 $c = DB_DataObject::factory('custinfo');
123 cust_number = 'MGCREDITCARD'
125 cust_number= 'MGPAYPAL'
127 cust_number = 'MGDEPOSIT'
130 $customers = $c->fetchAll('cust_id', 'cust_number');
132 if(count(array_values($customers)) != 3){
133 $this->jerr("error occur on getting MGCREDITCARD, MGPAYPAL and MGDEPOSIT customers". print_R($customers,true));
136 foreach($customers as $id=>$n) {
139 $this->errmsg = array();
141 $no_split = count(file($content)) > 500 ? false : true; // small file just group by customers.. big file group by the first two char of the order number!
143 if (!HTML_FlexyFramework::get()->cli && !$no_split) {
144 $roo->jerr("file is too large to upload - please send to admin to import");
150 while(false !== ($n = fgetcsv($fh,10000, ',', '"'))) {
151 if (!strlen(implode('', $n))) {
155 foreach ($col as $k => $c){
157 if($c == 'ORDER NUMBER'){
162 $r[$c] = substr($n[$k], -4) * 10000 + $row;
165 if($c == 'ORDER DATE'){
166 $r[$c] = date('Y-m-d',strtotime(str_replace('/', '-', $n[$k])));
173 $od = $r['ORDER DATE'];
175 if ($od != $r['ORDER DATE']) {
176 $this->jerr("the file contains orders for multiple days first was $od, found {$r['ORDER DATE']}
177 - either download again, or remove the extra lines");
181 $index = $no_split ? 1 : floor($r['ORDER NUMBER'] / 1000000);
183 if($r['PAYMENT TYPE'] == 'creditcard' || $r['PAYMENT TYPE'] == 'free'){
184 $rows['MGCREDITCARD'][$index][] = $r;
189 if($r['PAYMENT TYPE'] == 'paypal_express'){
190 $rows['MGPAYPAL'][$index][] = $r;
193 if($r['PAYMENT TYPE'] == 'directdeposit_au'){
194 $rows['MGDEPOSIT'][$index][] = $r;
197 $this->jerr("invalid payment type: " .$r['PAYMENT TYPE'] );
206 foreach($customers as $cid => $cname) {
209 if (empty($rows[$cname])) {
212 foreach ($rows[$cname] as $k => $v){
213 $this->transObj = DB_DataObject::Factory('cohead');
214 $this->transObj->query('BEGIN');
215 $this->transObj->lockTables();
216 list( $ltotal, $lbilled) = $this->createOrder($cid, $cname, $v, ($no_split) ? '' : ($k));
218 if (!empty($this->errmsg)) {
219 $this->jerr(implode("\n", $this->errmsg));
222 $this->transObj->query('COMMIT');
223 $this->transObj = false;
225 $GLOBALS['_DB_DATAOBJECT']['RESULTS'] = array();
226 $GLOBALS['_DB_DATAOBJECT']['RESULTFIELDS'] = array();
236 $msg = empty($this->ok_message) ? 'data imported successfully' : $this->ok_message;
238 $this->addEvent('MAGENTO', false, $msg);
240 $this->jok($msg . ' TOTAL: '. number_format($total,2) . ' BILLED: ' .number_format($billed, 2) . ' Time:' . (microtime(true) - $this->timer) . ' seconds' );
244 function createOrder($cust_id, $cust_name, $rows, $suffix = '')
247 $this->debugLog("creating order $cust_name - $suffix");
248 $customer = DB_DataObject::Factory('custinfo');
249 $customer->get($cust_id);
250 $location_id = DB_DataObject::Factory('location')->defaultByItemsite()->itemsite_location_id;
253 $this->warning[] = "No products sold for " . $cust_name;
257 $order_date = $rows[0]['ORDER DATE'];
260 'MGCREDITCARD' => 'MGC',
262 'MGDEPOSIT' => 'MGD',
267 static $oldvoid = array();
268 $nox = $prefix[$cust_name] . str_replace('-', '', $order_date);
269 if (!in_array($nox, $oldvoid)) {
270 $this->debugLog('void the non-x sales order');
272 $co = DB_DataObject::factory('cohead');
273 if($co->get('cohead_number',$nox)){
274 $this->voidInvAndShipments($co);
280 $suffix = 'x'.$suffix;
283 $cohead_number = $prefix[$cust_name] . str_replace('-', '', $order_date) . $suffix;
285 $co = DB_DataObject::factory('cohead');
287 if($co->get('cohead_number',$cohead_number)){
289 $this->voidInvAndShipments($co);
293 $this->debugLog('creating new head');
294 // create cntct if not exists
296 'cntct_first_name' => $customer->cust_name,
297 'cust_id' => $cust_id,
299 'cntct_name' => $customer->cust_name
301 // simple address for customer..
304 'addr_line1' => 'Address for ' . $customer->cust_name . ' account'
306 $cn = $this->checkcntctAndaddr($cntct, $addr);
309 $this->jerr('error occur on getting the contact of ' . $customer->cust_name);
311 $sr = $this->authUser->salesrep();
313 $co = DB_DataObject::factory('cohead');
316 'cohead_cust_id' => $cust_id,
317 'cohead_number' => $cohead_number,
318 'cohead_cust_id_cust_name' => $cust_name,
319 'cohead_orderdate' => $order_date,
320 'cohead_targetdate' => $order_date,
321 'cohead_location_src' => $location_id,
322 'cohead_terms_id' => $customer->cust_terms_id,
323 'cohead_salesrep_id' => empty($sr->salesrep_id) ? $customer->cust_salesrep_id : $sr->salesrep_id,
324 'cohead_billto_cntct_id' => $cn->pid(),
325 'cohead_shipto_cntct_id' => $cn->pid(),
326 'cohead_curr_id' => $customer->cust_curr_id,
327 'cohead_taxzone_id' => $customer->cust_taxzone_id
331 foreach($co->defaults() as $k=>$v) {
332 if (!isset($co->$k)) {
339 $co->updateAddress();
345 $this->debugLog('adding lines');
348 $total_discount = 0.0;
351 $billitems = array();
352 $invoice_total = 0.0;
353 $toShipment = array();
355 $totaldiscounted_inctax = 0.0;
357 $aftertax_line_total = 0.0;
359 $this->debugLog("number of items " . count($rows));
360 foreach ($rows as $r){
362 // do we have the itme??
363 $i = DB_DataObject::factory('item')->lookupSKU($r['ITEM NAME']);
365 $this->errmsg[] = $r['ITEM NAME'] . ' not found';
369 // delete the old line numbers..
370 $coitem = DB_DataObject::factory('coitem');
371 if($coitem->get('coitem_linenumber', $r['ORDER NUMBER'])){ // coitem not exist
375 $coitem = DB_DataObject::factory('coitem');
378 $itemsite = $i->itemsite();
380 $this->jerr("product {$i->item_number} has not been created correctly - missing itemsite");
383 $itemtotal += $r['ITEM TOTAL'];
385 $coitem_custprice = round(($r['ITEM TOTAL'] / $r['QUANTITY']) * (10 / 11) ,3);
386 $base_coitem_custprice = $coitem_custprice;
389 $aftertax_line_total += round($coitem_custprice * $r['QUANTITY'] * 1.1,2 );
391 // $r['DISCOUNT'] is negative number
392 //if(($r['SUBTOTAL'] - $r['DISCOUNT'] == 0.0) || $r['PAYMENT TYPE'] == 'free' ) {
393 if(($coitem_custprice == 0.0) || ($r['SUBTOTAL'] - $r['DISCOUNT'] == 0.0) || $r['PAYMENT TYPE'] == 'free' ) {
398 $coitem_price = $coitem_custprice * ($r['SUBTOTAL'] / ($r['SUBTOTAL'] - $r['DISCOUNT']));
399 $coitem_price = round($coitem_price ,3);
402 // for rounding tests...
405 $totaldiscounted_inctax += ( $r['ITEM TOTAL'] - round($coitem_price * $r['QUANTITY'] * 1.1,2 ));
407 $coitem->setFrom(array(
408 'coitem_cohead_id' => $co->pid(),
409 'coitem_linenumber' => $r['ORDER NUMBER'],
410 'coitem_itemsite_id' => $itemsite->pid(),
411 'coitem_qtyord' => $r['QUANTITY'],
412 'coitem_price' => $coitem_price,
413 'coitem_custprice' => $coitem_custprice,
414 'coitem_qtyshipped' => 0,
415 'coitem_location_src' => $co->cohead_location_src,
416 'coitem_shipto_id' => $co->cohead_shipto_id, // $shipto,
417 'coitem_scheddate' => $r['ORDER DATE']
419 foreach($coitem->defaults() as $k=>$v) {
420 if (empty($coitem->$k)) {
426 if(!$coitem->coitem_id){
427 $this->errmsg[] = $r['ITEM NAME'] . ' error occur on insert';
432 $toShipment[$coitem->pid()] = $coitem;
434 if(substr($r['ORDER NUMBER'],-4,4) == 1){
435 $total += $r['TOTAL'] ;
436 $total_discount += $r['DISCOUNT'] ;
438 if ( $r['PAYMENT TYPE'] == 'free' ) {
441 $freight += ($r['FREIGHT'] * 1.0);
442 $delivery += ($r['FREIGHT'] * 10 / 11);
446 $x['cobill_coitem_id'] = $coitem->pid();
447 $x['cobill_qty'] = $coitem->coitem_qtyord;
449 $billitems[] = (object)$x;
451 $invoice_total += round($coitem->coitem_qtyord * $coitem->coitem_price,2);
457 if (!empty($this->errmsg)) {
461 // last row - create shipment...
463 if(count($toShipment)){
465 'curr' => $co->cohead_curr_id
467 $this->orderShipments($toShipment,$d);
471 $this->debugLog('sorting out discounts');
473 $coitem = DB_DataObject::factory('coitem');
474 $coitem->get('coitem_cohead_id', $co->pid());
475 if($coitem->find(true)){
476 $coitem->updatePretaxDiscount($this);
480 $this->debugLog('sorting out delivery');
481 // make the rounding here..
482 $delivery = $freight * (10/11);
484 $i = dB_DataObject::Factory('item');
485 if (!$i->get('item_number', 'Z-DELIVERY CHARGE')) {
486 $this->jerr("delivery charge not found");
488 $itemsite = $i->itemsite();
490 // add z-Delivery Charge coz it's taxable
491 $coitem = DB_DataObject::factory('coitem');
492 $coitem->coitem_cohead_id = $co->pid();
493 $coitem->coitem_itemsite_id = $itemsite->pid();
494 $coitem->coitem_linenumber = 9999998;
495 if (!$coitem->find(true)) {
497 $coitem->setFrom(array(
498 'coitem_cohead_id' => $co->pid(),
499 'coitem_linenumber' => 9999998, // need a line number..
500 'coitem_itemsite_id' => $coitem->coitem_itemsite_id,
501 'coitem_qtyord' => 1,
502 'coitem_price' => round($delivery,3),
503 'coitem_custprice' => round($delivery,3),
504 'coitem_qtyshipped' => 0,
505 'coitem_location_src' => $co->cohead_location_src,
506 'coitem_shipto_id' => $co->cohead_shipto_id, // $shipto,
507 'coitem_scheddate' => $order_date
510 foreach($coitem->defaults() as $k=>$v) {
511 if (empty($coitem->$k)) {
517 $co_old = clone($coitem);
518 $coitem->setFrom(array(
519 'coitem_price' => round($delivery,3),
520 'coitem_custprice' => round($delivery,3),
521 'coitem_location_src' => $co->cohead_location_src,
522 'coitem_shipto_id' => $co->cohead_shipto_id, // $shipto,
523 'coitem_scheddate' => $order_date
525 $coitem->update($co_old);
529 // add freigth total to invoice..
530 $invoice_total += round($delivery,2) ;
534 $x['cobill_coitem_id'] = $coitem->pid();
535 $x['cobill_qty'] = $coitem->coitem_qtyord;
537 $billitems[] = (object)$x;
543 $i = DB_DataObject::Factory('item');
544 if (!$i->get('item_number', 'Z-LIST-DISCOUNT')) {
545 $this->jerr("Z-LIST-DISCOUNT not found");
547 $itemsite = $i->itemsite();
549 $coitem = DB_DataObject::factory('coitem');
550 $coitem->coitem_cohead_id = $co->pid();
551 $coitem->coitem_itemsite_id = $itemsite->pid();
552 if($coitem->find(true)){
554 $x['cobill_coitem_id'] = $coitem->pid();
555 $x['cobill_qty'] = $coitem->coitem_qtyord;
557 $billitems[] = (object)$x;
558 $invoice_total = $invoice_total + ($coitem->coitem_qtyord * $coitem->coitem_price);
560 $co_old = clone ($co);
562 'cohead_misc' => $coitem->coitem_qtyord * $coitem->coitem_price * -1,
563 'cohead_misc_descript' => 'DISCOUNT'
565 $co->update($co_old);
569 $cobapply_list = array();
570 // check gift voucher
572 $gift = $itemtotal + $freight - $total + $total_discount;
574 if(false && $gift > 5){ // check credit memo
576 $cmhead = DB_DataObject::factory('cmhead');
577 $cmhead->setFrom(array(
578 'cmhead_number' => $cmhead->nextNumber(),
579 'cmhead_cust_id' => $co->cohead_cust_id,
580 'cmhead_billto_cntct_id' => $co->cohead_billto_cntct_id,
581 'cmhead_taxzone_id' => $co->cohead_taxzone_id,
582 'cmhead_curr_id' => $co->cohead_curr_id,
583 'cmhead_salesrep_id' => $co->cohead_salesrep_id,
584 'cmhead_docdate' => $co->cohead_targetdate,
585 'cmhead_location_id' => $co->cohead_location_src
588 foreach($cmhead->defaults() as $k=>$v) {
589 if (empty($cmhead->$k)) {
597 $this->jerr('error occur on insert a credit memo');
600 $i = dB_DataObject::Factory('item');
601 if (!$i->get('item_number', 'Z-DISCOUNT-VOUCHER')) {
602 $this->jerr("Z-DISCOUNT-VOUCHER not found");
604 $itemsite = $i->itemsite();
606 $cmitem = DB_DataObject::factory('cmitem');
607 $cmitem->setFrom(array(
608 'cmitem_cmhead_id' => $cmhead->pid(),
609 'cmitem_linenumber' => 999997,
610 'cmitem_itemsite_id' => $itemsite->pid(),
611 'cmitem_qtycredit' => 1,
612 'cmitem_qtyreturned' => 1,
613 'cmitem_unitprice' => $gift,
614 'cmitem_taxtype_id' => $cmitem->sqlValue("gettaxtypeid('Taxable'::text)"),
615 'cmitem_comments' => $i->item_descrip1,
618 foreach($cmitem->defaults() as $k=>$v) {
619 if (empty($cmitem->$k)) {
626 $this->jerr('error occur on insert Z-DISCOUNT-VOUCHER to credit memo');
629 $cmhead->post($this);
631 $aropen = DB_DataObject::factory('aropen');
632 $aropen->aropen_cust_id = $customer->pid();
633 $aropen->aropen_doctype = 'C';
634 $aropen->aropen_docnumber = $cmhead->cmhead_number;
635 $cobapply_list = $aropen->fetchAll('aropen_id');
636 if(count($cobapply_list) != 1){
637 $this->jerr('error occur on getting aropen');
642 $this->debugLog('creating bill');
644 // create the invoice for each magento order
645 $cobmisc = DB_DataObject::factory('cobmisc');
647 $cobmisc->setFrom(array(
648 'cobmisc_cohead_id' => $co->pid(),
649 'cobmisc_invcdate' => $order_date,
650 'cobmisc_shipdate' => $order_date
653 $cobmisc->cobmisc_taxtype_id = $cobmisc->sqlValue("gettaxtypeid('Taxable'::text)");
656 $t = $cobmisc->factory('cobmisc');
657 $t->query("SELECT createBillingHeader({$co->pid()}) AS cobmisc_id");
660 $cobmisc->cobmisc_id = $t->cobmisc_id;
661 $cobmisc->updateItems($billitems);
663 // apply the credit memo..
664 if (!empty($cobapply_list)) {
665 $cobmisc->updateCobApply($this,$cobapply_list);
670 $t = $cobmisc->factory('cobmisc');
671 $t->get($cobmisc->cobmisc_id);
674 // fetch again so it should have invoice..
675 $t = $cobmisc->factory('cobmisc');
676 $t->get($cobmisc->cobmisc_id);
678 $invoice = $t->invchead();
680 $aropen = $invoice->aropen();
684 if (round($total,2) != round($aropen->aropen_amount,2)) {
685 $this->jerr("TOTAL $total != {$aropen->aropen_amount}" .
687 'itemtotal' => $itemtotal,
688 'aftertax_line_total' => $aftertax_line_total,
690 'total_discount' => $total_discount,
691 'freight' => $freight,
694 'totaldiscounted_inctax' => $totaldiscounted_inctax,
695 'totaldiscounted_b4tax' => $totaldiscounted_inctax * (10/11),
696 'freight_b4tax' => $freight * (10/11),
701 //print_R($aropen);$this->jerr("fixme");
703 return array( $total, $aropen->aropen_amount);
707 function checkcntctAndaddr($cntct,$addrs)
709 $cn = DB_DataObject::factory('cntct');
711 if(!$cn->get('cntct_first_name', $cntct['cntct_first_name'])){ // contact not exists
712 $cn->setFrom($cntct);
713 $cn->cntct_crmacct_id = $cn->sqlValue("(SELECT crmacct_id FROM crmacct WHERE crmacct_cust_id = {$cntct['cust_id']})");
718 if(!$cn->cntct_addr_id){ // addr not exists
719 $addr = DB_DataObject::Factory('addr');
720 $addr->setFrom($addrs);
725 $cn->cntct_addr_id = $addr->pid();
733 function checkshiptoinfo($customer, $cntct)
735 $sh = DB_DataObject::Factory('shiptoinfo');
736 $sh->shipto_cntct_id = $cntct->pid();
737 $sh->shipto_addr_id = $cntct->cntct_addr_id;
738 if ($sh->find(true)) {
743 'shipto_cust_id' => $cust_id,
744 'shipto_name' => $cntct->cntct_name,
745 'shipto_salesrep_id'=> $customer->cust_salesrep_id,
746 'shipto_active' => true,
747 'shipto_adefault' => false,
748 'shipto_shipchrg_id' => $customer->cust_shipchrg_id,
749 'shipto_taxzone_id' => $customer->cust_taxzone_id,
750 'shipto_shipform_id' => $customer->cust_shipform_id,
751 'shipto_commission' => 0,
752 'shipto_shipzone_id' => $customer->cust_taxzone_id
762 function orderShipments($toShipments,$d)
764 $this->debugLog('creating shipments');
766 $ids = array_keys($toShipments);
767 $c = array_pop($toShipments);
769 $cc = DB_DataObject::factory('coitem');
770 $cc->coitem_cohead_id = $c->coitem_cohead_id;
774 $shipitems = array();
775 while ($cc->fetch()){ // this query will take about 6 secs...
777 $itemsite = $cc->itemsite();
778 // skip non-stock items..
779 if (!$itemsite->itemsite_stocked) {
783 $x['shipitem_orderitem_id'] = $cc->pid();
784 $x['shipitem_qty'] = 0;
785 if(in_array($cc->pid(), $ids)){
786 $x['shipitem_qty'] = $cc->coitem_qtyord;
788 $shipitems[] = (object)$x;
791 $sh = DB_DataObject::factory('shiphead');
796 'shiphead_shipdate' => $c->coitem_scheddate,
797 'shiphead_order_id' => $c->coitem_cohead_id,
798 'shiphead_sfstatus' => 'N',
799 'shiphead_location_id' => $c->coitem_location_src,
800 'shiphead_shipto_id' => $c->coitem_shipto_id,
801 //'shiphead_number' => $cohead->cohead_number . substr($c->coitem_linenumber, 0, 4),
802 'shiphead_order_type' => 'SO',
803 'shiphead_freight' => 0, //$d['freight'],
804 'shiphead_freight_curr_id' => $d['curr'],
805 'shiphead_notes' => '' // $r['SHIP NOTE']
807 $sh->beforeInsert(array('shiphead_number' => 'Automatic'),$this);
808 //$this->jerr("about to create shipment: " . $sh->shiphead_number);
812 $sh->updateItems($shipitems, $this);
817 function voidInvAndShipments($co)
819 $this->debugLog('deelting old invoices / shipments');
820 $invoices = $co->cobmiscs();
822 foreach($invoices as $i) {
823 $i->void($this, true);
827 $invoices = $co->cobmiscs();
828 foreach($invoices as $i) {
829 $i->void($this,true);
831 // delete the shipments...
832 $shipheads = $co->shipheads();
834 foreach($shipheads as $s) {
836 if (!empty($s->shiphead_shipped) && !empty($s->shiphead_shipdate)) {
837 $res = $s->unconfirm($this,true);
840 $this->jerr("ship unconfirm failed:" . $res);
844 if (!empty($s->shiphead_shipdate)) { // 395.43042492867 secs...
845 $res = $s->void($this,true); // void shipitem will take 0.1 sec for each... a little bit long time...
848 $this->jerr("ship voiding failed" . $res) ;
860 // Gift Wrapping not found
861 // Gift Wrapping not found
863 // Gift Wrapping not found