DataObjects/Invhist_transfer.php
[Pman.Xtuple] / DataObjects / Invhist_transfer.php
1 <?php
2 /**
3  * Table Definition for invhist
4  */
5 require_once 'DB/DataObject.php';
6
7 class Pman_Xtuple_DataObjects_Invhist_transfer extends DB_DataObject 
8 {
9     ###START_AUTOCODE
10     /* the code below is auto generated do not remove the above tag */
11
12     public $__table = 'invhist_transfer';             // table name
13     public $invhist_transfer_id;                      // int4(4)  not_null default_nextval%28%28invhist_invhist_id_seq%29%3A%3Aregclass%29 primary_key
14     public $invhist_transfer_from;             // int4(4)  
15     public $invhist_transfer_to;               // timestamptz(8)  default_%28now%29%3A%3Atimestamp%286%29%20with%20time%20zone
16     public $invhist_transfer_number;               // bpchar(-1)  
17     public $invhist_transfer_descrip;                  // numeric(-1)  
18     public $invhist_transfer_posted;                  // numeric(-1)  
19     public $invhist_transfer_transdate;
20     public $invhist_transfer_arrivaldate;
21     public $invhist_transfer_recvgrp_id;
22     public $invhist_transfer_void;
23     public $invhist_transfer_salesrep_id;
24     public $invhist_transfer_delivery_note;              //TEXT
25
26
27     /* the code above is auto generated do not remove the tag below */
28     ###END_AUTOCODE
29       
30     function toEventString()
31     {
32         return $this->invhist_transfer_number;
33     }
34     function applyFilters($q, $au, $roo)
35     {
36         
37         if (!empty($q['_createFromRecv'])) {
38             $rg = DB_DataObject::Factory('recvgrp');
39             $rg->get($q['_createFromRecv']);
40             
41             $ih = $this->factory($this->tableName());
42             $ih->autoJoin();
43             $ih->get($this->createFromRecvGroup($roo,$rg));
44             $roo->addEvent("CREATEFROMRECV", $this);
45             
46             $roo->jok($ih->toArray());
47             
48         }
49         
50         $this->selectAdd("
51             (SELECT SUM(invhist_transfer_item.invhist_transfer_item_qty) FROM invhist_transfer_item
52                 WHERE  invhist_transfer_item_invhist_transfer_id =  invhist_transfer_id ) as qty,
53             (
54                 SELECT
55                         COALESCE(ROUND(SUM(invdetail_qty)), 0) 
56                 FROM 
57                         invdetailview
58                 WHERE 
59                             (
60                                 invdetail_invhist_id IN (
61                                                             SELECT 
62                                                                     invhist_transfer_invhist_id
63                                                             FROM
64                                                                     invhist_transfer_item
65                                                             WHERE  
66                                                                     invhist_transfer_item_invhist_transfer_id = invhist_transfer_id
67                                                             )
68                             OR
69                                 (
70                                         invhist_comments = invhist_transfer_number
71                                     OR
72                                         invhist_comments = invhist_transfer_number || ' REVERSED'
73                                 )
74                                 
75                             )
76                         AND
77                             invdetail_location_id = invhist_transfer_to
78                         AND
79                             (invfifo_void IS NULL OR invfifo_void = 0)
80             ) AS moved_qty
81             
82         ");
83         
84         if (!empty($q['query']['location_id'])) {
85             $l = (int) $q['query']['location_id'];
86             $this->whereAdd("
87                    invhist_transfer_from = $l OR  invhist_transfer_to = $l 
88                             
89                             
90                     ");
91         }
92          if (!empty($q['query']['invhist_transfer_number'])) {
93             $l = $this->escape( $q['query']['invhist_transfer_number']) ;
94             $this->whereAdd("
95                    invhist_transfer_number like '$l%' 
96                     ");
97         }
98         
99         if(!empty($q['query']['dateSel'])){
100             $this->invhist_transfer_transdate = "{$q['query']['dateSel']}";
101         }
102         
103         
104         if (!empty($q['_download'])) {
105             //$this->autoJoin();
106             if (!$this->get($q['_download'])) {
107                 $roo->jerr("Invalid URL = fetch failed.");
108             }
109             return $this->download($roo);
110         }
111         
112         // add the customer type chars..
113          
114         $this->selectAdd("
115                         (SELECT charass_getvalue('C', location_cust_id  ,'INTERNALCOMPANY')
116                                 FROM location where location_id  = invhist_transfer_to LIMIT 1
117                         )
118                          as cust_to_internalcompany,
119                          
120                         (SELECT charass_getvalue('C', location_cust_id  ,'INTERNALCOMPANY')
121                                 FROM location where location_id  = invhist_transfer_from LIMIT 1
122                         )
123                          as cust_from_internalcompany
124         ");
125         if (!empty($q['cust_to_internalcompany'])) {
126             $this->whereAdd("
127                             (SELECT charass_getvalue('C', location_cust_id  ,'INTERNALCOMPANY')
128                                 FROM location where location_id  = invhist_transfer_to LIMIT 1
129                         ) = '{$this->escape($q['cust_to_internalcompany'])}'
130                 ");
131             
132             
133         }
134         
135     }
136     
137     
138     
139     function verifyLocations($roo, $req = array())
140     {
141         
142         if (empty($this->invhist_transfer_from)) {
143             $roo->jerr("Transfer from location  is not set");
144         }
145         if (empty($this->invhist_transfer_to)) {
146             $roo->jerr("Transfer to location is not set");
147         }
148         
149         if($this->invhist_transfer_from == $this->invhist_transfer_to){
150             $roo->jerr("Transfer from location is same as transfer to location?!");
151         }
152         
153         $src = DB_DataObject::factory('location');
154         $src->get($this->invhist_transfer_from);
155         $dest = DB_DataObject::factory('location');
156         $dest->get($this->invhist_transfer_to);
157         $scust = $src->customer();
158         $dcust = $dest->customer();
159         
160         if (!$dcust) {
161             $roo->jerr("the destination location specified does not have a customer associated with it.");
162         }
163         if (!$scust) {
164             $roo->jerr("the source location specified does not have a customer associated with it.");
165         }
166         
167         if (strlen($scust->char('INTERNALCOMPANY')) ) {
168             
169             
170             $roo->jerr("Transfering from remote not allowed - the other site must create a transfer to you.". print_R($req,true));
171         }
172         
173     }
174     
175     function beforeInsert($request,$roo) 
176     {
177         $this->verifyLocations($roo, $request);
178         
179         /*
180          *  check to see if the delivery notes is allow blank
181          *  if the shiphead location id is same as the default_location, then all blank, otherwise, MUST fill it in...
182          */
183         if(empty($this->invhist_transfer_delivery_note)){
184             $l = DB_DataObject::factory('location');
185             $l = $l->defaultConfigLocation();
186             
187             if($this->invhist_transfer_from != $l->pid()){
188                 $roo->jerr("You must fill in the transfer delivery notes!");
189             }
190         }
191         
192         if (($this->invhist_transfer_number == 'AUTOMATIC') || empty($this->invhist_transfer_number)) {
193             $this->invhist_transfer_number = $this->generateNumber();
194             
195         }
196         
197     }
198     
199     function generateNumber($name=false)
200     {
201         if (!$name) {
202             $it = DB_DataObject::Factory('invhist_transfer');
203             $it->selectAdd();
204             $it->selectAdd( 'MAX(substring(invhist_transfer_number from 3)::int) as result');
205             $it->whereAdd( "invhist_transfer_number LIKE 'IT%'");
206             $it->whereAdd( "invhist_transfer_number NOT LIKE 'ITR%'");
207             $it->find(true);
208             $num = isset($it->result) ? $it->result + 1 : 1;
209             return 'IT'. $num;
210         }
211         // otherwise we do it based on suffixes
212         $it = DB_DataObject::Factory('invhist_transfer');
213         if (!$it->get('invhist_transfer_number', $name)) {
214             return $name;
215         }
216         $n = 1;
217         while ($n < 100) {
218             $it = DB_DataObject::Factory('invhist_transfer');
219             if (!$it->get('invhist_transfer_number', $name.'-'.$n)) {
220                return $name.'-'.$n;
221             }   
222             
223             
224             $n++;
225         }
226         
227         
228     }
229     
230     
231     
232     
233     function post($roo,$r = array())
234     {
235         if ($this->invhist_transfer_posted) {
236               $roo->jerr("It's already posted");
237         }
238           
239         $lf = $this->location_from();
240         if (!$lf) {
241             $roo->jerr("from location does not exist?");
242         }
243         
244         $lt = $this->location_to();
245         
246         if (!$lt) {
247             $roo->jerr("to location does not exist?");
248         }
249         
250         
251         // check that this internal company does not match us 
252          $ourdb = substr($this->database(), -2);
253          
254           
255         $ltc = $lt->customer()->char('INTERNALCOMPANY');
256         
257         
258         if (strlen($ltc) && $ourdb != $ltc) {
259             
260             $this->checkLocationStock($roo);
261             
262             return $this->postInterCompany($roo);
263         }
264         
265         $roo->sessionState(0);
266         
267         
268         $this->query("
269             SELECT invhist_transfer_post({$this->pid()})
270             ");
271         $roo->addEvent("POSTED", $this);
272         $roo->jok("POSTED");
273        
274     }
275     
276     
277     function void($roo,$r)
278     {  
279         $this->verifyLocations($roo);
280           
281         $lf = $this->location_from();
282         if (!$lf) {
283             $roo->jerr("from location does not exist?");
284         }
285         
286         if (strlen($lf->customer()->char('INTERNALCOMPANY'))) {
287             $roo->jerr("Transfering from remote not allowed - the other site must create a transfer to you.");
288         }
289         
290         
291         $lt = $this->location_to();
292         if (!$lt) {
293             $roo->jerr("to location does not exist?");
294         }
295         if (strlen($lt->customer()->char('INTERNALCOMPANY'))) {
296             return $roo->jerr("You can not void a inter-company transfer - ask the other company to transfer the stock back.");
297         }
298         
299         
300         $this->query("
301             SELECT invhist_transfer_void({$this->pid()})
302             ");
303             
304         $t = DB_DataObject::factory('invhist_transfer');
305         $t->get($this->pid());
306         $t->invhist_transfer_void = 1;
307         $t->update($this);
308
309         $roo->addEvent("VOIDED", $this);
310         $roo->jok("VOIDED");
311        
312     }
313     
314     
315     function beforeUpdate($old, $request, $roo)
316     {
317         if (!empty($request['_void'])) {
318             $this->factory('cohead')->lockTables();
319             $this->void($roo,$request);
320         }
321         
322         if(!empty($request['_copy'])){
323             $this->factory('cohead')->lockTables();
324             $this->copy($roo);
325         }
326         
327         if(!empty($request['_fix'])){
328             $this->factory('cohead')->lockTables();
329             $this->fixTransfer($roo);
330         }
331         
332         // would be nice if these where in the trigger for posted..
333         if (!empty($request['_post'])) {
334             
335            $this->factory('cohead')->lockTables();
336             $this->verifyLocations($roo, $request);
337             $this->post($roo, $request);
338         }
339         
340         $this->verifyLocations($roo, $request);
341         
342         /*
343          *  check to see if the delivery notes is allow blank
344          *  if the shiphead location id is same as the default_location, then all blank, otherwise, MUST fill it in...
345          */
346         if(empty($this->invhist_transfer_delivery_note)){
347             $l = DB_DataObject::factory('location');
348             $l = $l->defaultConfigLocation();
349             
350             if($this->invhist_transfer_from != $l->pid()){
351                 $roo->jerr("You must fill in the transfer delivery notes!");
352             }
353         }
354         
355         if ($this->invhist_transfer_posted) {
356             $roo->jerr("Transfer is posted, please void first");
357         }
358         if (isset($request['transfer_items'])) {
359             $this->updateItems(json_decode($request['transfer_items']), $roo);
360              
361         }
362         
363         
364     }
365     
366     function onInsert($request,$roo) 
367     {
368          if (isset($request['transfer_items'])) {
369             $this->updateItems(json_decode($request['transfer_items']), $roo);
370              
371         }
372         
373         
374     }
375     
376     
377     function items($curr=false, $with_purchase_dt=false)
378     {
379         
380         
381         $base = DB_DataObject::Factory('curr_symbol');
382         $base = $base->base();
383       
384         
385         if (!$curr) {
386             $curr= $base;
387         }
388         $r= DB_DataObject::Factory('invhist_transfer_item');
389         $r->invhist_transfer_item_invhist_transfer_id = $this->pid();
390         $r->autoJoin();
391         $r->joinAddItem();
392         
393         $r->selectAdd("
394              currtocurr({$base->pid()} , {$curr->pid()}, stdcost(item_id) , '{$this->invhist_transfer_transdate}'::date) as item_stdcost
395         ");
396         
397         if ($with_purchase_dt) {
398             
399             $r->selectAdd(" COALESCE((
400                         SELECT
401                             currtocurr(pohead_curr_id, {$curr->pid()}, poitem_unitprice, '{$this->invhist_transfer_transdate}'::date)
402                         FROM
403                             poitem
404                         LEFT JOIN
405                             pohead
406                         ON
407                             poitem_pohead_id = pohead_id
408                         WHERE
409                            pohead_orderdate  <= '$with_purchase_dt'::date
410                         AND
411                             poitem_itemsite_id = itemsite_id
412                         ORDER BY
413                             poitem_duedate DESC
414                         LIMIT 1
415                         
416                 ), -1) as poitem_unitprice
417             ");
418         }
419         
420         $r->orderBy('invhist_transfer_item_line ASC');
421         $r->find();
422         
423         $ret = array();
424         while ($r->fetch()) {
425             /*
426              * use invhist_transfer_item_id as the index
427              * after check, there is no other place using this
428              * 
429              * $ret[$r->invhist_transfer_item_line] = clone($r);
430              */
431          
432             $ret[$r->invhist_transfer_item_id] = clone($r);
433         }
434         
435         return $ret;
436         
437     }
438     /**
439      *
440     *  row of
441     *   qty | itemsite_id | line
442      *
443      **/
444     
445     function updateItems($rows, $roo)
446     {
447         $old = $this->items();
448         
449         $lt = $this->location_to();
450         
451         if (!$lt) {
452             $roo->jerr("to location does not exist?");
453         }
454         
455         $ourdb = substr($this->database(), -2);
456           
457         $ltc = $lt->customer()->char('INTERNALCOMPANY');
458         
459         foreach($rows as $r)
460         {
461             if (isset($old[$r->id])) {
462                 $o = clone($old[$r->id]);
463                 $o->setFrom(array(
464                     'invhist_transfer_item_itemsite_id' => $r->itemsite_id,
465                     'invhist_transfer_item_qty' => $r->qty,
466                     'invhist_transfer_item_unit_price' => (strlen($ltc) && $ourdb != $ltc) ? $r->price * 1 : $this->sqlValue('NULL')
467                 ));
468                 $o->update($old[$r->id]);
469                 unset($old[$r->id]);
470                 continue;
471                 
472             }
473             // no old line exists.. - create a new one..
474             $r->price = empty($r->price) ?  '' : $r->price;
475             $o = DB_DataObject::Factory('invhist_transfer_item');
476             $o->setFrom(array(
477                 
478                 'invhist_transfer_item_itemsite_id' => $r->itemsite_id,
479                 'invhist_transfer_item_qty' => $r->qty,
480                 'invhist_transfer_item_invhist_transfer_id' => $this->pid(),
481                 'invhist_transfer_item_line' => $r->line, // very trusting?
482                 'invhist_transfer_item_unit_price' => (strlen($ltc) && $ourdb != $ltc) ? $r->price * 1 : $this->sqlValue('NULL')
483             ));
484             $o->insert();
485             
486         }
487         if (!empty($old)) {
488             foreach($old as $line=>$r) {
489                 $r->delete();
490             }
491         }
492           
493     }
494     function download($roo)
495     {
496         $lt = $this->location_to();
497         
498         if (!$lt) {
499             $roo->jerr("to location does not exist?");
500         }
501         
502         $ourdb = substr($this->database(), -2);
503           
504         $ltc = $lt->customer()->char('INTERNALCOMPANY');
505         
506         $q = array();
507         if (strlen($ltc) && $ourdb != $ltc) {
508             $q['_inter_transfer'] = 1;
509         }
510         
511         $r= DB_DataObject::Factory('invhist_transfer_item');
512         $r->invhist_transfer_item_invhist_transfer_id = $this->pid();
513         $r->autoJoin();
514         $r->applyFilters($q, $roo->authUser, $roo);
515         $r->orderBy('invhist_transfer_item_line ASC');
516         
517         require_once 'Pman/Core/SimpleExcel.php';
518         $s = new Pman_Core_SimpleExcel(
519             $r->fetchAll(false,false,'toArray'), array(
520                 'head' => array(
521                         array( "Date:", date('Y-m-d', strtotime($this->invhist_transfer_transdate))),
522                         array( "Arrival Date:", date('Y-m-d', strtotime($this->invhist_transfer_arrivaldate))),
523                         array( "Reference:", $this->invhist_transfer_number),
524                         array( "From:", $this->invhist_transfer_from_location_name),
525                         array( "To:", $this->invhist_transfer_to_location_name),
526                 ),
527                 'cols' => array(
528                     array(
529                         'header'=> "Line",
530                         'dataIndex'=> 'invhist_transfer_item_line',
531                         'width'=>  75,
532                             //'renderer' => array($this, 'getThumb')
533                     ),
534                     array(
535                         'header'=> "Item Code",
536                         'dataIndex'=> 'item_number',
537                         'width'=>  100,
538                     //'renderer' => array($this, 'getThumb')
539                     ),
540                     array(
541                         'header'=> "Description",
542                         'dataIndex'=> 'item_descrip1',
543                         'width'=>  300,
544                     //'renderer' => array($this, 'getThumb')
545                     ),
546                     array(
547                         'header'=> "Quantity",
548                         'dataIndex'=> 'invhist_transfer_item_qty',
549                         'width'=>  50,
550                     //'renderer' => array($this, 'getThumb')
551                     ),
552                     array(
553                         'header'=> "Currency",
554                         'dataIndex'=> 'invhist_transfer_item_curr_name',
555                         'width'=>  50,
556                     //'renderer' => array($this, 'getThumb')
557                     ),
558                     array(
559                         'header'=> "Unit Price",
560                         'dataIndex'=> 'invhist_transfer_item_unit_price',
561                         'width'=>  50,
562                     //'renderer' => array($this, 'getThumb')
563                     ),
564                 ),
565                 
566                 'workbook' => 'InvTransfer'
567             
568         ));
569         $s->send($this->invhist_transfer_number.date("-d-M-Y").'.xls');
570         
571          
572         
573     }
574     
575     function location_from()
576     {
577         $l = DB_DataObject::Factory('location');
578         if (!$l->get($this->invhist_transfer_from)) {
579             return false;
580         }
581         return $l;
582         
583     }
584     function location_to()
585     {
586         $l = DB_DataObject::Factory('location');
587         if (!$this->invhist_transfer_to || !$l->get($this->invhist_transfer_to)) {
588             return false;
589         }
590         return $l;
591     }
592   
593     
594     
595     function postInterCompany($roo)
596     {
597         
598         //$roo->jerr("disabled until correct prices are uploaded");
599         
600         // which office is it going to...
601         $lt = $this->location_to();
602         if (!$lt) {
603             $roo->jerr("to location does not exist?");
604         }
605         
606         $c = $lt->customer();
607         
608         if(!$c){
609             $roo->jerr("could not find customer");
610         }
611         
612         $cur = $c->priceListCurrency($roo);
613         
614         $target_office = $c->char('INTERNALCOMPANY');
615         
616         if (!strlen($target_office)) {
617              $roo->jerr("target location does not exist");
618         }
619         
620         
621         $url = 'http://localhost'.HTML_FlexyFramework::get()->page->rootURL .'/'.
622                 strtolower($target_office) .'.php/Roo/Location?lookup[location_name]=' . urlencode($lt->location_name);
623         
624         $res = json_decode(file_get_contents($url),true);
625         
626         if(!$res['success'] || !count($res['data'])){
627             $roo->jerr('Missing location ' . $lt->location_name . 'in ' . $target_office);
628         }
629         if (!empty($res['data']['location_cust_id_char_internalcompany']) &&
630                 strtolower($target_office ) != strtolower($res['data']['location_cust_id_char_internalcompany'])) {
631             
632             $roo->jerr("Remote location is not flagged as a local location");
633         }
634        
635         // pircing...
636         if (empty($this->invhist_transfer_price)) {
637             $roo->jerr("transfer pricing not set");
638         }
639         
640         $priceLists = array();
641         
642         
643         $dt = date('Y-m-d', strtotime( $this->invhist_transfer_transdate));
644         // items with purhcase prices. 
645         $allItems = $this->items($cur, $dt);
646         
647         switch($this->invhist_transfer_price) {
648             case 'PRICELIST': 
649                  
650                 $bad_items = array();
651                 // slow!!!
652                 
653                 foreach ($allItems as $row){
654                     // || $row->invhist_transfer_item_unit_price == 0.00 << why support this??
655                     if(!empty($row->invhist_transfer_item_unit_price)){
656                         $priceLists[$row->invhist_transfer_item_itemsite_id] = $row->invhist_transfer_item_unit_price;
657                         continue;
658                     }
659                     $itemsite = DB_DataObject::factory('itemsite');
660                     if(!$itemsite->get('itemsite_id', $row->invhist_transfer_item_itemsite_id)){
661                         $roo->jerr('error occur on getting item with reference ' . $row->invhist_transfer_item_itemsite_id);
662                     }
663                     
664                     $ipsass = DB_DataObject::factory('ipsass');
665                     $ipsass->query("SELECT itemprice(
666                                     {$itemsite->itemsite_item_id}, 
667                                     {$c->pid()}, 
668                                     null, 
669                                     {$row->invhist_transfer_item_qty}, 
670                                     {$cur->pid()}, 
671                                      '{$dt}'::date
672                                 ) AS result");
673                     $ipsass->fetch();
674                     
675                     if ( empty($ipsass->result) || $ipsass->result == 0.0) {
676                         $bad_items[] = $itemsite->itemsite_item_id;
677                         continue;
678                     }
679                     
680                     $priceLists[$row->invhist_transfer_item_itemsite_id] = $ipsass->result;
681                 }
682                 
683                 if (!empty($bad_items)) {
684                     $item = DB_DataObject::Factory('item');
685                     $item->whereAddIn('item_id', $bad_items, 'int');
686                     $ar = $item->fetchAll('item_number');
687                     $roo->jerr("These items do not have prices " . implode(', ', $ar));
688                     
689                 }
690                  
691                 
692                 break;
693             
694             case 'LASTPLUS':
695                 foreach($allItems as $rn => $row) {
696                     $priceLists[$row->invhist_transfer_item_itemsite_id] =
697                         $row->poitem_unitprice > 0.0 ?  ($row->poitem_unitprice  * 1.10 * 1.15 ) :    ($row->item_stdcost * 1.15);
698                 }
699                 break;
700             
701             case 'STDCOST':
702                 foreach($allItems as $rn => $row) {
703                     // not allowed to post empty stdcosts...
704                     $priceLists[$row->invhist_transfer_item_itemsite_id] = round($row->item_stdcost,2) == 0.00 ? 0.01 : $row->item_stdcost ;
705                 }
706                 break;
707             
708             default:
709                 $roo->jerr("invalid price type: ". $this->invhist_transfer_price);
710         }
711                     
712              // print_R($priceLists);exit;      
713                     
714                     
715         
716         $items = array();
717         $adt = date('Y-m-d', strtotime($this->invhist_transfer_arrivaldate));
718         $bad_items = array();
719         foreach($allItems as $rn => $row)
720         {
721             
722             if (empty($priceLists[$row->invhist_transfer_item_itemsite_id])) {
723                 $bad_items[] = $row->item_number;
724                 continue;
725             }
726             $items[] = array(
727                 'line' => $row->invhist_transfer_item_line,
728                 'item_number' => $row->item_number,
729                 '_itemsite_id' => $row->invhist_transfer_item_itemsite_id,
730                 'qty' => $row->invhist_transfer_item_qty,
731                 'cost' => round($priceLists[$row->invhist_transfer_item_itemsite_id],2),
732                 'currency' => $cur->curr_name,
733                 'duedate' => $adt
734                 
735             );
736             
737             
738         }
739         if (!empty($bad_items)) {
740             $roo->jerr("no prices for ". implode(', ', $bad_items));
741         }
742         
743         $roo->sessionState(0);
744         // if this fails and remote succeeds then we are borked, so we do the local stuff first,
745         // fail if necessary.. before doing remote..
746         $this->factory('cohead')->lockTables();
747         $this->createLocalInvoice($roo,$target_office, $items);
748         
749         //$roo->jok("an invoice should have been created");
750         //$roo->jerr("testing");
751         $this->createRemotePO($roo,$target_office, $items);
752         
753         $roo->sessionState(1); // unless jok does sesson stuff may not need to start session again..  
754         // flag this as posted..
755         
756         $items = $this->items();
757         foreach ($items as $item){
758             $i = clone ($item);
759             $item->invhist_transfer_item_unit_price_default = $i->invhist_transfer_item_unit_price;
760             $item->update($i);
761         }
762         
763         $old = clone($this);
764         $this->invhist_transfer_posted  = true;
765         $this->update($old);
766     
767         
768         
769         $roo->addEvent("POSTED", $this);
770         $roo->jok("CREATED");
771         
772     }
773     
774     
775     
776     
777     function createRemotePO($roo,$target_office, $items )
778     {
779         $target_office = strtolower($target_office);
780         
781         $lt = $this->location_to();
782         
783         /*
784          * check that the target location is actually a local location
785          */
786         
787         $ourdb = substr($this->database(), -2);
788         if ($target_office == $ourdb) {
789             $roo->jerr("target office matches our office?");
790         }
791         
792         $cust = $lt->customer();
793         
794         if (!$cust) {
795             $roo->jerr("could not find customer");
796         }
797         
798         $cur = $cust->priceListCurrency($roo);
799         
800         $po_prefix = 'XF-'. strtoupper(substr($this->database(),-2)).'-'. strtoupper($target_office) .'-';
801         
802         
803         $url = 'http://localhost'.HTML_FlexyFramework::get()->page->rootURL .'/'. $target_office .'.php';
804       // $roo->jerr("posting to $url");
805         
806         $dt = date('Y-m-d', strtotime($this->invhist_transfer_transdate));
807
808         require_once 'HTTP/Request.php';
809        
810         $req = new HTTP_Request( $url . '/Roo/Pohead' );
811         $req->setMethod(HTTP_REQUEST_METHOD_POST);
812         $req->addPostData( array(
813                 '_is_xfer' => 1,
814                 'pohead_number' => $po_prefix . $this->invhist_transfer_number,  // invoice should match number...
815                 'invhist_transfer_number' => $this->invhist_transfer_number,  // invoice should match number...
816                 'pohead_orderdate' => $dt,
817                 
818                 'pohead_released' => $dt,
819                 //'invchead_invcdate' => $this->shiphead_shipdate,
820                 '_vendor_internal_company' =>  substr($this->database(),-2) ,
821                 'curr_name' => $cur->curr_name,
822                  
823                 'items' => json_encode($items),
824                 'target_location' => $lt->location_name
825           
826         ));
827          //$roo->jerr( print_r($req->_postData,true));
828         //$roo->jerr( $req->_url->getURL() );
829         
830         $res = $req->sendRequest();
831         
832         if (is_a($res,'PEAR_Error')) {
833             $roo->jerr("REMOTE REQUEST RETURNED: ". $res->toString());
834         }
835         $res = json_decode($req->getResponseBody());
836         
837         if (!is_object($res)) {
838             $roo->jerr("REMOTE REQUEST RETURNED: ". $req->getResponseBody());
839         }
840       
841         if (!$res->success) {
842             $roo->jerr("REMOTE REQUEST RETURNED: ". $res->errorMsg);
843         }
844         
845         return (array) $res->data;
846     }
847      
848     function createLocalInvoice($roo, $target_office, $items)
849     {
850         
851         $invc = DB_DataObject::Factory('invchead');
852         $invc->createFromTransfer($roo, $target_office, $this, $items);
853         
854         
855     }
856     
857     
858     
859     function createFromRecvGroup($roo, $rg)
860     {
861         
862          
863         
864         
865         $new = $this->factory($this->tableName());
866         $new->setFrom(array(
867             'invhist_transfer_number' => $this->generateNumber('ITR-' . $rg->pid()),
868             'invhist_transfer_transdate' => date('Y-m-d'),
869             'invhist_transfer_descrip' => 'Created from PO : '  . $rg->pohead()->pohead_number . "\nItem Reciept " . $rg->recvgrp_number,
870             'invhist_transfer_from' => $rg->recvgrp_location_id,
871             'invhist_transfer_recvgrp_id' =>$rg->pid()
872         ));
873         $new->insert();
874         foreach($rg->items() as $line=>$i) {
875             $i->qty = $i->recv_qty;
876             $i->itemsite_id = $i->recv_itemsite_id;
877             $i->line = $i->recv_orderitem_id_poitem_linenumber;
878             $up[] = $i;
879         }
880         $new->updateItems($up, $roo);
881         
882         return $new->pid();
883         
884     }
885     
886     function checkLocationStock($roo)
887     {
888         if(empty($roo->bootLoader->Xtuple['prevent_negative'])){
889             return;
890         }
891         
892         $items = $this->items();
893         
894         $stock = array();
895         
896         foreach ($items as $item){
897             if(empty($item->invhist_transfer_item_qty)){
898                 continue;
899             }
900             
901             $balance = $item->itemsite()->checkLocationStock($this->invhist_transfer_from);
902
903             if(empty($balance) || $balance < $item->invhist_transfer_item_qty){
904                 $stock[] = $item->itemsite()->item()->item_number;
905             }
906         }
907
908         if(count($stock)){
909             $roo->jerr("These items have negative stock " . implode(', ', $stock));
910         }
911     }
912     
913     function copy($roo)
914     {
915         $copy = $this->toArray();
916         
917         $t = DB_DataObject::factory('invhist_transfer');
918         $t->setFrom($copy);
919         $t->setFrom(array(
920             'invhist_transfer_id' => 0,
921             'invhist_transfer_posted' => false,
922             'invhist_transfer_void' => false,
923             'invhist_transfer_number' => $t->generateNumber()
924         ));
925         
926         $t->insert();
927         
928         $i = DB_DataObject::factory('invhist_transfer_item');
929         $i->selectAdd();
930         $i->selectAdd("
931             0 AS id,
932             invhist_transfer_item_itemsite_id AS itemsite_id,
933             invhist_transfer_item_line AS line,
934             invhist_transfer_item_qty AS qty,
935             COALESCE(invhist_transfer_item_unit_price,0) AS price
936         ");
937         $i->invhist_transfer_item_invhist_transfer_id = $this->pid();
938         $items = $i->fetchAll();
939         
940         $t->updateItems($items, $roo);
941         
942     }
943     
944     function fixTransfer($roo)
945     {
946         $invdetail = DB_DataObject::factory('invfifo');
947         
948         $invdetail->query("
949             UPDATE
950                     invfifo
951             SET
952                     invfifo_void = 0
953             WHERE
954                     invfifo_invdetail_id IN (
955                                                 SELECT
956                                                         invdetail_id
957                                                 FROM
958                                                         invdetailview
959                                                 WHERE
960                                                         invhist_comments = '{$this->invhist_transfer_number}'
961                                                     OR
962                                                         invhist_comments = '{$this->invhist_transfer_number}' || ' REVERSED'
963                                             )
964                         
965         ");
966         
967         $invdetail = DB_DataObject::factory('invdetail');
968         
969         $invdetail->query("
970             SELECT
971                     invfifo_update_from_invdetail(invdetail_id, TRUE)
972             FROM
973                     invdetailview
974             WHERE
975                     invhist_comments = '{$this->invhist_transfer_number}'
976                 OR
977                     invhist_comments = '{$this->invhist_transfer_number}' || ' REVERSED'
978         ");
979         
980         $roo->jok('FIXED');
981     }
982     
983  }