Fix #7123 - getting abra ready to test
[Pman.Xtuple] / VerifyMigrate.php
1 <?php
2 require_once 'Verify.php';
3 class Pman_Xtuple_VerifyMigrate extends Pman_Xtuple_Verify
4 {
5     
6     function get()
7     {
8         ini_set('memory_limit', '500M');
9         
10         if (isset($_REQUEST['prods'])) {
11             
12             $data = $this->txRecords($_REQUEST['loc'], explode(',',$_REQUEST['prods']));
13             echo json_encode($data);exit;
14             
15             
16         }
17         
18         if (isset($_REQUEST['prod'])) {
19             
20             $data = $this->txRecordsAll($_REQUEST['loc'],  $_REQUEST['prod'],isset($_REQUEST['day']) ? $_REQUEST['day'] : false);
21             echo json_encode($data);exit;
22             
23             
24         }
25         
26         
27         $sd = strtoupper(array_pop(explode('xtuple', HTML_FlexyFramework::get()->database)));
28         
29         
30         $lprefix  = preg_match('/(lsg\.php|lhk.php)$/', $this->baseURL) ? 'l' : '';
31         
32         
33         
34         //DB_DataObject::debugLevel(1);
35         // we need to
36         // A) grab the stock levels from the old database.
37         
38         // B) grab the stock levels from the new database
39         
40         // compare the values..
41         // for comparison:
42         
43             // use  "Location: XXXX  Product : XXXX" = $n
44             // we might even be able to use array_diff between the two..
45         $il = DB_DataObject::Factory('itemloc');
46         $il->autoJoin(array(
47                 'links' => array(
48                     'itemloc_location_id' => 'location:location_id',
49                     'itemloc_itemsite_id' => 'itemsite:itemsite_id',
50                     
51                 )
52         ));
53         $il->selectAdd();
54         $il->selectAdd("
55             'Location : ' ||  join_itemloc_location_id_location_id.location_name ||
56             ' Product : ' || (SELECT item_number FROM item WHERE
57                         item_id = join_itemloc_itemsite_id_itemsite_id.itemsite_item_id LIMIT 1) as pn,
58                     itemloc_qty
59                        
60                        ");
61         $il->whereAdd('itemloc_qty <> 0.0');
62         $data = $il->fetchAll('pn', 'itemloc_qty');
63         ksort($data);
64         
65         if ($sd != 'HK') {
66             // we only report on HK data..
67             echo json_encode($data);
68             exit;
69         }
70         // hard codE?
71         $har = explode('/', realpath(__FILE__));
72         $home = '/home/'. $har[2];
73         $fn = "$home/Dropbox/xtuple_working/old_database_snapshot/stock.json";
74        // var_dump($fn);exit;
75         $base_data = (array)json_decode(file_get_contents($fn));
76         //echo '<PRE>'; print_r($base_data);exit;
77         //var_dump($base_data['Location : Dymocks-CB Product : DM05001']);
78         //exit;
79         //print_r($base_data);exit;
80         // run all the child processes...
81         //
82         //echo $cmd;exit;
83         $other_data = (array) json_decode(file_get_contents(
84                     "http://localhost/xtuple/{$lprefix}sg.php/Xtuple/VerifyMigrate"));
85
86                     
87         
88         $core = array_merge($data,$base_data, $other_data);
89         ksort($core);
90         
91         $out = array();
92         
93         
94         
95         
96         $out[] = array("location / sku", "OLD", "HK", "SG", "difference");
97         // merge the data and produce a sensible report..
98         $errors = array();
99         foreach($core as $k=>$blah) {
100             $row = array(
101                 $k,
102                 isset($base_data[$k]) ? $base_data[$k] : 0,
103                 isset($data[$k]) ? $data[$k] : 0,
104                 isset($other_data[$k]) ? $other_data[$k] : 0,
105             );
106             $row[4] = $row[1] - ($row[2] + $row[3]);
107             
108             if ($row[4] != 0 ) {
109                 $out[] = $row;
110                 $errors[$row[0]] =  $row[1];
111             }
112              
113             
114         } 
115         
116         $error_ar = array();
117         foreach($errors as $r=>$qty) {
118             
119             $exp = explode(' Product : ', preg_replace('/^Location :/', '', $r));
120             //print_R( $exp); 
121             list($loc, $prod) = $exp;
122             $loc = trim($loc);
123             if (!isset($error_ar[$loc])) {
124                 $error_ar[$loc] = array();
125             }
126             $error_ar[$loc][] = $prod;
127         }
128        // echo '<PRE>';print_R($error_ar);exit;
129        
130         //echo '<PRE>';
131       
132         foreach($error_ar as $loc => $prods) {
133             if ($loc != 'OLL') {
134               //  continue;
135             }
136             $out = array_merge($out,$this->processMismatch($loc, $prods));
137         }
138         
139         //die("got this far");
140       
141          foreach($out as $o) {
142             if (!is_array($o)) {
143                 var_dump($o);exit;
144             }
145           }
146       
147         header('Content-type: text/csv');
148         header( 'Content-Disposition: attachment;filename=stock_report-'.date('Y-m-d').'.csv');
149         $fh = fopen('php://output','w');
150         foreach($out as $o) {
151                fputcsv($fh, $o);
152             
153         }
154         exit;
155         
156          
157         /*
158         $el = array();
159         $eltot = 0;
160         $locmax = 0;
161         $totmax = 0;
162         foreach($errors as $r=>$qty) {
163             
164             
165             $exp = explode(' Product : ', preg_replace('/^Location :/', '', $r));
166             //print_R( $exp); 
167             list($loc, $prod) = $exp;
168             
169             $loc = trim($loc);
170             $prod = trim($prod);
171             
172             $el[$loc] = isset($el[$loc]) ? $el[$loc] : 0;
173             if ($locmax && $el[$loc] > $locmax) {
174                 continue;
175             }
176             if ($totmax && $eltot > $totmax) {
177                 break;
178             }
179                         
180             $el[$loc]++;
181             $eltot++;
182             
183             $url = 'http://localhost/xtuple/hk.php/Roo/invdetail';
184             $args = $this->toParams(array(
185                 'query[item_number]'=> trim($prod),
186                 'query[location_name]'=> trim($loc),
187                 '_with_item'=>'1',
188                 'sort'=>'invhist_transdate,invdetail_id',
189                 'dir'=>'ASC',
190                 
191                 
192                 'csvCols[0]' => 'invhist_transdate',
193                 'csvCols[1]' => 'invhist_docnumber',
194                 'csvCols[2]' => 'invhist_ordnumber',
195                 'csvCols[3]' => 'invdetail_qty',
196                 'csvCols[4]' => 'invdetail_bydate_qty',
197                 'csvCols[5]' => 'invhist_comments',
198                 
199                 'csvTitles[0]' => 'Date',
200                 'csvTitles[1]' => 'Doc number',
201                 'csvTitles[2]' => 'Order no.',
202                 'csvTitles[3]' => 'Qty',
203                 'csvTitles[4]' => 'Qty After',
204                 'csvTitles[5]' => 'comments',
205                 'start' => 0,
206                 'limit' => 9999
207                 
208                 
209             ));
210             
211             
212             
213             fwrite($fh, "\n\n-- ". $r ." ,,Expecting:, $qty\n");
214                    
215                    
216             fwrite($fh, file_get_contents("http://localhost/xtuple/{$lprefix}hk.php/Roo/invdetail?$args"));
217             fwrite($fh, file_get_contents("http://localhost/xtuple/{$lprefix}sg.php/Roo/invdetail?$args"));
218         */
219             /*
220              $rows = $this->fcsv("http://localhost/xtuple/{$lprefix}hk.php/Roo/invdetail?$args");
221             $head = array_shift($rows);
222             fputcsv($fh, $head);
223             
224             $add = $this->fcsv("http://localhost/xtuple/{$lprefix}sg.php/Roo/invdetail?$args");
225             array_shift($add);
226             $rows += $add;
227             
228             usort($rows, function($a, $b) {
229                 $aa =strtotime($a[0]);
230                 $bb = strtotime($b[0]);
231                 if ($aa == $bb) return 0;
232                 return $a < $b ? -1 : 1;
233                 
234             });
235             $ltot = 0;
236             foreach($rows as $row)
237             {
238                 $ltot += $row[3];
239                 $row[4] = $ltot;
240                 fputcsv($fh, $row);
241                
242                 
243             }
244             */
245             
246         /*    
247                                
248             
249         }
250         
251         */
252         
253         exit;
254         
255         
256         
257         
258         
259         
260         echo '<PRE>';print_r($data);
261         
262         exit;
263         
264     }
265     function fcsv($fn)
266     {
267         $handle = fopen($fn, "r");
268         while (($data = fgetcsv($handle)) !== false) {
269             $ret[] = $data;
270         }
271         return $ret;
272     }
273     
274     function fullTx($loc,$pods) {
275         
276         // old style lists..
277         return array(array('old style tx log'));
278         
279     }
280     
281     /*
282      process:
283      we have a list of location / products that do not match
284      
285      1. load the full tx list from the database. (grouping by day) from both databases.
286      2. load the csv for that.
287      3. compare the day change totals
288      4. any day that does not match
289        - output the tx records from our system
290        - output the tx records from netsuite (csv)
291      
292      
293      
294     */
295      
296     function processMismatch($loc, $prods)
297     {
298         
299         // we need to cache the results from this..
300         $cache = '/tmp/stock-'. $loc . '-' . date('Y-m-d');
301         if (file_exists($cache)) {
302             return unserialize(file_get_contents($cache));
303         }
304         
305         
306         
307         $loc_data  = $this->loadCSV($loc );
308         
309         if (empty($loc_data)) {
310             //echo "SKIP - not data for $loc\n";
311             $ret = array(array("LOCATION: $loc"));
312             foreach($prods as $prod) {
313                 $ret[] =  array("-- ONLY XT DATA: $prod");
314                 
315                 $data =$this->xtData($loc, $prod,false);
316                 $head = false;
317                 foreach($data as $tx) {
318                         if (!$head) {
319                            $ret[] = array_keys($tx);
320                            $head = true;
321                        }
322                        $ret[] = array_values($tx);
323                    }
324             }
325             file_put_contents($cache,serialize($ret));
326             exit('<meta http-equiv="refresh" content="0; url=' . urldecode('http://'.$_SERVER['HTTP_HOST'].'/xtuple/hk.php/Xtuple/VerifyMigrate?ts='.urlencode($loc)) . '"/>
327                  
328                  Processing more data...... ('. $loc .')
329                  
330                  '); 
331             
332              exit;
333             echo "DONE CACHE $loc\n";exit;
334             return $ret;
335         }
336         
337         
338         $ourtx = $this->txRecords($loc, $prods);
339         
340         $sd = strtoupper(array_pop(explode('xtuple', HTML_FlexyFramework::get()->database)));
341         
342         
343         $lprefix  = preg_match('/(lsg\.php|lhk.php)$/', $this->baseURL) ? 'l' : '';
344         
345          
346         $other = (array) json_decode(file_get_contents(
347                     "http://localhost/xtuple/{$lprefix}sg.php/Xtuple/VerifyMigrate?loc=".urlencode($loc).'&prods='.implode(',', $prods)));
348         
349         // merge them..
350         
351         foreach($other as $prod=>$data) {
352             $data = (array) $data;
353             foreach($data as $day=>$qty) {
354                 if (isset($ourtx[$prod][$day])) {
355                     $ourtx[$prod][$day] += $qty;
356                     continue;
357                 }
358                 $ourtx[$prod][$day] = $qty;
359                 
360             }
361             
362         }
363          $ret = array();
364         
365         //print_R($ourtx);exit;
366         // we should now have day summaries for them all.. compare it to the data in the database.
367         
368         foreach($ourtx as $prod=>$data) {
369             if (!isset($loc_data[$prod])) {
370                // $ret[] =  array("NO location data for $loc / $prod");
371                // continue;
372                 
373             }
374             $prod_data  = isset($loc_data[$prod]) ? $loc_data[$prod] : array();
375            // echo "$prod\n";
376             $bad_day = array();
377             $prod_changes = $this->dayChanges($prod_data);
378             //echo "XTUPLE:\n";
379             //print_R($data);
380             //echo "NS:\n";
381             //print_R($prod_changes);
382             
383             
384             foreach($prod_changes as $day =>$qty) {
385                 if (!isset($data[$day]) || $data[$day] != $qty) {
386                     $ns = isset($data[$day] ) ? $data[$day]  : 0 ;
387                     //echo "$day : XTUPLE: $qty : NS $ns\n";
388                     
389                     
390                     $bad_day[] = $day;
391                 }
392             }
393             foreach($data as $day =>$qty) {
394                 if (!isset($prod_changes [$day]) || $prod_changes [$day] != $qty) {
395                     $xt  = isset($prod_changes [$day] ) ? $prod_changes [$day]  : 0 ;
396                     //echo "$day : XTUPLE: $xt  : NS $qty\n";
397                     
398                     $bad_day[] = $day;
399                 }
400             }
401             
402             $bad_day = array_unique($bad_day);
403             $bad_days[$prod] = $bad_day;
404             
405             //print_R($bad_day);exit;
406             
407             
408         }
409         // we now have a list of bad days for that product..
410         
411         
412        
413        // print_r($bad_days);
414         foreach($bad_days as $prod => $days) {
415             $prod_data  = isset($loc_data[$prod]) ? $loc_data[$prod] : array();
416              $ret[] = array();
417             $ret[] = array('LOCATION : ' . $loc . ' Product : ' . $prod);
418             $ret[] = array("--- NETSUITE: ");
419             $head =false;
420             foreach($days as $day) {
421                 
422                 
423                 $day_data = isset($prod_data[$day]) ? $prod_data[$day] : array();
424                 
425                 
426                 
427                 
428                 foreach($day_data  as $tx) {
429                     if (!$head) {
430                         $ret[] = array_keys($tx);
431                         $head = true;
432                     }
433                     $ret[] = array_values($tx);
434                 }
435                   
436                 // now dump the data from 
437                 
438             }
439              $ret[]  = array();
440              $ret[] = array("--- MIGRATED:  ");
441               $head =false;
442                 
443             foreach($days as $day) {
444                 
445                 
446                 $day_data = isset($prod_data[$day]) ? $prod_data[$day] : array();
447                 
448                 $data = $this->xtData($loc, $prod, $day);
449                 foreach($data as $tx) {
450                      if (!$head) {
451                         $ret[] = array_slice(array_keys($tx), 0,7);
452                         $head = true;
453                     }
454                     $ret[] = array_values($tx);
455                 }   
456                 
457                 // now dump the data from 
458                 
459             }
460             $ret[] = array();     
461             $ret[]  = array();
462             
463         }
464         
465         file_put_contents($cache,serialize($ret));
466        exit('<meta http-equiv="refresh" content="0; url=' . urldecode('http://'.$_SERVER['HTTP_HOST'].'/xtuple/hk.php/Xtuple/VerifyMigrate?ts='.urlencode($loc)) . '"/>'); 
467         echo "DONE CACHE $loc\n";exit;
468         return $ret;
469         print_R($ret);
470                 
471                 exit;
472         
473         exit;
474             
475              
476         
477     }
478     
479     function xtData($loc, $prod,$day) {
480         //var_dump($loc);
481         
482         
483         
484         $locs = $this->txRecordsAll($loc,$prod,$day);
485          $sd = strtoupper(array_pop(explode('xtuple', HTML_FlexyFramework::get()->database)));
486         
487         
488         $lprefix  = preg_match('/(lsg\.php|lhk.php)$/', $this->baseURL) ? 'l' : '';
489         //echo "http://localhost/xtuple/{$lprefix}sg.php/Xtuple/VerifyMigrate?loc=".urlencode($loc).'&prod='.$prod.'&day='.$day;
490         //print_r($loc);exit;
491         $remote =  (array) json_decode(file_get_contents(
492                     "http://localhost/xtuple/{$lprefix}sg.php/Xtuple/VerifyMigrate?loc=".urlencode($loc).'&prod='.$prod . ($day !== false ? ('&day='.$day) : '')));
493         foreach($remote as $line) {
494             $locs[] = (array)$line;
495         }
496         //print_r($locs);exit;
497         $GLOBALS['_DB_DATAOBJECT']['RESULTFIELDS'] = array();
498          $GLOBALS['_DB_DATAOBJECT']['RESULTS'] = array();
499         
500         return $locs;
501         
502     }
503     
504     
505     function txRecordsAll($loc, $prod, $day)
506     {
507         $ret = array();
508     
509         //DB_DataObject::debugLevel(1);
510         $d = DB_DataObject::factory('invdetail');
511         $d->autoJoin();
512         $d->applyFilters(array(
513             'query' => array(
514                     'item_number'=> trim($prod),
515                     'location_name'=> trim($loc),
516             ),
517              '_with_item'=>'1',
518              
519              
520              
521         ),$this->authUser, $this);
522         if ($day !== false) {
523             $d->whereAdd("invhist_transdate::date = '$day'");
524         }
525         $d->selectAdd();
526         $d->selectAdd('
527             join_invhist.invhist_transdate,
528             join_invhist.invhist_docnumber,
529             join_invhist.invhist_ordnumber,
530              invdetail_qty  ,
531             invdetail_bydate(invdetail_id) AS  invdetail_bydate_qty ,
532             join_invhist.invhist_comments 
533         ');
534         
535         $d->orderBy('invdetail_id ASC');
536         
537         
538         return $d->fetchAll(false,false, 'toArray');
539         
540         
541     }
542      
543     function txRecords($loc, $prods)
544     {
545         $ret = array();
546         foreach($prods as $prod) {
547            // DB_DataObject::debugLevel(1);
548             $d = DB_DataObject::factory('invdetail');
549             $d->autoJoin();
550             $d->applyFilters(array(
551                 'query' => array(
552                         'item_number'=> trim($prod),
553                         'location_name'=> trim($loc),
554                 ),
555                  '_with_item'=>'1',
556             ),$this->authUser, $this);
557             $d->orderBy('invhist_transdate ASC');
558             $d->selectAdd();
559             $d->selectAdd('distinct(invhist_transdate::date) as  invhist_transdate, sum(invdetail_qty) as invdetail_qty');
560             $d->groupBy('invhist_transdate');
561             $ret[$prod]  = $d->fetchAll('invhist_transdate', 'invdetail_qty');
562             //exit;
563         }
564         return $ret;
565         
566     }
567     
568     
569     
570     function dayChanges($cvsdata)
571     {
572         
573         
574         foreach($cvsdata as $day => $rows) {
575         
576             $qty = 0;
577             foreach($rows as $row) {
578                 $qty += $row['Qty.'];
579             }
580             $ret[$day] = $qty;
581         }
582         return $ret;
583         
584     }
585     
586     // returns array of day -> [ tx, tx, tx ]
587     
588     function loadCSV($loc)
589     {
590      
591     
592         $file = '/home/alan/netsuite_accounts/iad-'. $loc. '.csv';
593         if (!file_exists($file)) {
594            // echo "NO FILE: $file\n";
595             $files[$loc]= array();
596             return array();
597         }
598         
599         $fh = fopen($file ,'r');
600         if (!$fh) {
601             die("failed to open $file\n");
602         }
603         
604         $head = false;
605         $out = array();
606         $product = false;
607         
608         while (false !== ($row = fgetcsv($fh, 4000))) {
609             if ($head === false) {
610                 if (trim($row[0]) != 'Item') {
611                     continue;
612                 }
613                 
614                 $head = array();
615                 foreach($row as $v) {
616                     $head[] = trim($v);
617                 }
618                 continue;
619             }
620            // print_R($head);exit;
621             $line = array();
622             // skip the intro line.
623             if ($row[0] == 'Inventory Item') {
624                 continue;
625             
626             }
627             if (preg_match('/^Total /', $row[0])) {
628                 continue;
629             }
630             if (!strlen(trim($row[1]))) {
631                 // then it's a new product.
632                 $product = $row[0];
633                 $out[$product] = array( );
634                 continue;
635             }
636             if (empty($product)) {
637                 continue;
638             }
639             
640             // got a normal line.
641             $day = date('Y-m-d', strtotime(implode('-', array_reverse(explode('/', $row[1])))));
642             if (!isset($out[$product][$day])) {
643                 $out[$product][$day] = array();
644             }
645             
646             foreach($head as $i=>$k) {
647                 if ($k == 'Date') {
648                     $line[$k] = date('Y-m-d', strtotime(implode('-', array_reverse(explode('/', $row[$i])))));
649                     continue;
650                 }
651                 
652                 
653                 $line[$k] = trim($row[$i]);
654                     
655             }
656              $out[$product][$day][] = $line;
657              
658             
659         }
660         //print_R($out);exit;
661         return $out;
662         
663         
664     }
665     
666     
667     
668 }