3 * Table Definition for invhist
5 require_once 'DB/DataObject.php';
7 class Pman_Xtuple_DataObjects_Invhist_transfer extends DB_DataObject
10 /* the code below is auto generated do not remove the above tag */
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
27 /* the code above is auto generated do not remove the tag below */
30 function toEventString()
32 return $this->invhist_transfer_number;
34 function applyFilters($q, $au, $roo)
37 if (!empty($q['_createFromRecv'])) {
38 $rg = DB_DataObject::Factory('recvgrp');
39 $rg->get($q['_createFromRecv']);
41 $ih = $this->factory($this->tableName());
43 $ih->get($this->createFromRecvGroup($roo,$rg));
44 $roo->addEvent("CREATEFROMRECV", $this);
46 $roo->jok($ih->toArray());
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,
55 COALESCE(ROUND(SUM(invdetail_qty)), 0)
60 invdetail_invhist_id IN (
62 invhist_transfer_invhist_id
66 invhist_transfer_item_invhist_transfer_id = invhist_transfer_id
70 invhist_comments = invhist_transfer_number
72 invhist_comments = invhist_transfer_number || ' REVERSED'
77 invdetail_location_id = invhist_transfer_to
79 (invfifo_void IS NULL OR invfifo_void = 0)
84 if (!empty($q['query']['location_id'])) {
85 $l = (int) $q['query']['location_id'];
87 invhist_transfer_from = $l OR invhist_transfer_to = $l
92 if (!empty($q['query']['invhist_transfer_number'])) {
93 $l = $this->escape( $q['query']['invhist_transfer_number']) ;
95 invhist_transfer_number like '$l%'
99 if(!empty($q['query']['dateSel'])){
100 $this->invhist_transfer_transdate = "{$q['query']['dateSel']}";
104 if (!empty($q['_download'])) {
106 if (!$this->get($q['_download'])) {
107 $roo->jerr("Invalid URL = fetch failed.");
109 return $this->download($roo);
112 // add the customer type chars..
115 (SELECT charass_getvalue('C', location_cust_id ,'INTERNALCOMPANY')
116 FROM location where location_id = invhist_transfer_to LIMIT 1
118 as cust_to_internalcompany,
120 (SELECT charass_getvalue('C', location_cust_id ,'INTERNALCOMPANY')
121 FROM location where location_id = invhist_transfer_from LIMIT 1
123 as cust_from_internalcompany
125 if (!empty($q['cust_to_internalcompany'])) {
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'])}'
139 function verifyLocations($roo, $req = array())
142 if (empty($this->invhist_transfer_from)) {
143 $roo->jerr("Transfer from location is not set");
145 if (empty($this->invhist_transfer_to)) {
146 $roo->jerr("Transfer to location is not set");
149 if($this->invhist_transfer_from == $this->invhist_transfer_to){
150 $roo->jerr("Transfer from location is same as transfer to location?!");
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();
161 $roo->jerr("the destination location specified does not have a customer associated with it.");
164 $roo->jerr("the source location specified does not have a customer associated with it.");
167 if (strlen($scust->char('INTERNALCOMPANY')) ) {
170 $roo->jerr("Transfering from remote not allowed - the other site must create a transfer to you.". print_R($req,true));
175 function beforeInsert($request,$roo)
177 $this->verifyLocations($roo, $request);
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...
183 if(empty($this->invhist_transfer_delivery_note)){
184 $l = DB_DataObject::factory('location');
185 $l = $l->defaultConfigLocation();
187 if($this->invhist_transfer_from != $l->pid()){
188 $roo->jerr("You must fill in the transfer delivery notes!");
192 if (($this->invhist_transfer_number == 'AUTOMATIC') || empty($this->invhist_transfer_number)) {
193 $this->invhist_transfer_number = $this->generateNumber();
199 function generateNumber($name=false)
202 $it = DB_DataObject::Factory('invhist_transfer');
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%'");
208 $num = isset($it->result) ? $it->result + 1 : 1;
211 // otherwise we do it based on suffixes
212 $it = DB_DataObject::Factory('invhist_transfer');
213 if (!$it->get('invhist_transfer_number', $name)) {
218 $it = DB_DataObject::Factory('invhist_transfer');
219 if (!$it->get('invhist_transfer_number', $name.'-'.$n)) {
233 function post($roo,$r = array())
235 if ($this->invhist_transfer_posted) {
236 $roo->jerr("It's already posted");
239 $lf = $this->location_from();
241 $roo->jerr("from location does not exist?");
244 $lt = $this->location_to();
247 $roo->jerr("to location does not exist?");
251 // check that this internal company does not match us
252 $ourdb = substr($this->database(), -2);
255 $ltc = $lt->customer()->char('INTERNALCOMPANY');
258 if (strlen($ltc) && $ourdb != $ltc) {
260 $this->checkLocationStock($roo);
262 return $this->postInterCompany($roo);
265 $roo->sessionState(0);
269 SELECT invhist_transfer_post({$this->pid()})
271 $roo->addEvent("POSTED", $this);
277 function void($roo,$r)
279 $this->verifyLocations($roo);
281 $lf = $this->location_from();
283 $roo->jerr("from location does not exist?");
286 if (strlen($lf->customer()->char('INTERNALCOMPANY'))) {
287 $roo->jerr("Transfering from remote not allowed - the other site must create a transfer to you.");
291 $lt = $this->location_to();
293 $roo->jerr("to location does not exist?");
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.");
301 SELECT invhist_transfer_void({$this->pid()})
304 $t = DB_DataObject::factory('invhist_transfer');
305 $t->get($this->pid());
306 $t->invhist_transfer_void = 1;
309 $roo->addEvent("VOIDED", $this);
315 function beforeUpdate($old, $request, $roo)
317 if (!empty($request['_void'])) {
318 $this->factory('cohead')->lockTables();
319 $this->void($roo,$request);
322 if(!empty($request['_copy'])){
323 $this->factory('cohead')->lockTables();
327 if(!empty($request['_fix'])){
328 $this->factory('cohead')->lockTables();
329 $this->fixTransfer($roo);
332 // would be nice if these where in the trigger for posted..
333 if (!empty($request['_post'])) {
335 $this->factory('cohead')->lockTables();
336 $this->verifyLocations($roo, $request);
337 $this->post($roo, $request);
340 $this->verifyLocations($roo, $request);
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...
346 if(empty($this->invhist_transfer_delivery_note)){
347 $l = DB_DataObject::factory('location');
348 $l = $l->defaultConfigLocation();
350 if($this->invhist_transfer_from != $l->pid()){
351 $roo->jerr("You must fill in the transfer delivery notes!");
355 if ($this->invhist_transfer_posted) {
356 $roo->jerr("Transfer is posted, please void first");
358 if (isset($request['transfer_items'])) {
359 $this->updateItems(json_decode($request['transfer_items']), $roo);
366 function onInsert($request,$roo)
368 if (isset($request['transfer_items'])) {
369 $this->updateItems(json_decode($request['transfer_items']), $roo);
377 function items($curr=false, $with_purchase_dt=false)
381 $base = DB_DataObject::Factory('curr_symbol');
382 $base = $base->base();
388 $r= DB_DataObject::Factory('invhist_transfer_item');
389 $r->invhist_transfer_item_invhist_transfer_id = $this->pid();
394 currtocurr({$base->pid()} , {$curr->pid()}, stdcost(item_id) , '{$this->invhist_transfer_transdate}'::date) as item_stdcost
397 if ($with_purchase_dt) {
399 $r->selectAdd(" COALESCE((
401 currtocurr(pohead_curr_id, {$curr->pid()}, poitem_unitprice, '{$this->invhist_transfer_transdate}'::date)
407 poitem_pohead_id = pohead_id
409 pohead_orderdate <= '$with_purchase_dt'::date
411 poitem_itemsite_id = itemsite_id
416 ), -1) as poitem_unitprice
420 $r->orderBy('invhist_transfer_item_line ASC');
424 while ($r->fetch()) {
426 * use invhist_transfer_item_id as the index
427 * after check, there is no other place using this
429 * $ret[$r->invhist_transfer_item_line] = clone($r);
432 $ret[$r->invhist_transfer_item_id] = clone($r);
441 * qty | itemsite_id | line
445 function updateItems($rows, $roo)
447 $old = $this->items();
449 $lt = $this->location_to();
452 $roo->jerr("to location does not exist?");
455 $ourdb = substr($this->database(), -2);
457 $ltc = $lt->customer()->char('INTERNALCOMPANY');
461 if (isset($old[$r->id])) {
462 $o = clone($old[$r->id]);
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')
468 $o->update($old[$r->id]);
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');
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')
488 foreach($old as $line=>$r) {
494 function download($roo)
496 $lt = $this->location_to();
499 $roo->jerr("to location does not exist?");
502 $ourdb = substr($this->database(), -2);
504 $ltc = $lt->customer()->char('INTERNALCOMPANY');
507 if (strlen($ltc) && $ourdb != $ltc) {
508 $q['_inter_transfer'] = 1;
511 $r= DB_DataObject::Factory('invhist_transfer_item');
512 $r->invhist_transfer_item_invhist_transfer_id = $this->pid();
514 $r->applyFilters($q, $roo->authUser, $roo);
515 $r->orderBy('invhist_transfer_item_line ASC');
517 require_once 'Pman/Core/SimpleExcel.php';
518 $s = new Pman_Core_SimpleExcel(
519 $r->fetchAll(false,false,'toArray'), 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),
530 'dataIndex'=> 'invhist_transfer_item_line',
532 //'renderer' => array($this, 'getThumb')
535 'header'=> "Item Code",
536 'dataIndex'=> 'item_number',
538 //'renderer' => array($this, 'getThumb')
541 'header'=> "Description",
542 'dataIndex'=> 'item_descrip1',
544 //'renderer' => array($this, 'getThumb')
547 'header'=> "Quantity",
548 'dataIndex'=> 'invhist_transfer_item_qty',
550 //'renderer' => array($this, 'getThumb')
553 'header'=> "Currency",
554 'dataIndex'=> 'invhist_transfer_item_curr_name',
556 //'renderer' => array($this, 'getThumb')
559 'header'=> "Unit Price",
560 'dataIndex'=> 'invhist_transfer_item_unit_price',
562 //'renderer' => array($this, 'getThumb')
566 'workbook' => 'InvTransfer'
569 $s->send($this->invhist_transfer_number.date("-d-M-Y").'.xls');
575 function location_from()
577 $l = DB_DataObject::Factory('location');
578 if (!$l->get($this->invhist_transfer_from)) {
584 function location_to()
586 $l = DB_DataObject::Factory('location');
587 if (!$this->invhist_transfer_to || !$l->get($this->invhist_transfer_to)) {
595 function postInterCompany($roo)
598 //$roo->jerr("disabled until correct prices are uploaded");
600 // which office is it going to...
601 $lt = $this->location_to();
603 $roo->jerr("to location does not exist?");
606 $c = $lt->customer();
609 $roo->jerr("could not find customer");
612 $cur = $c->priceListCurrency($roo);
614 $target_office = $c->char('INTERNALCOMPANY');
616 if (!strlen($target_office)) {
617 $roo->jerr("target location does not exist");
621 $url = 'http://localhost'.HTML_FlexyFramework::get()->page->rootURL .'/'.
622 strtolower($target_office) .'.php/Roo/Location?lookup[location_name]=' . urlencode($lt->location_name);
624 $res = json_decode(file_get_contents($url),true);
626 if(!$res['success'] || !count($res['data'])){
627 $roo->jerr('Missing location ' . $lt->location_name . 'in ' . $target_office);
629 if (!empty($res['data']['location_cust_id_char_internalcompany']) &&
630 strtolower($target_office ) != strtolower($res['data']['location_cust_id_char_internalcompany'])) {
632 $roo->jerr("Remote location is not flagged as a local location");
636 if (empty($this->invhist_transfer_price)) {
637 $roo->jerr("transfer pricing not set");
640 $priceLists = array();
643 $dt = date('Y-m-d', strtotime( $this->invhist_transfer_transdate));
644 // items with purhcase prices.
645 $allItems = $this->items($cur, $dt);
647 switch($this->invhist_transfer_price) {
650 $bad_items = array();
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;
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);
664 $ipsass = DB_DataObject::factory('ipsass');
665 $ipsass->query("SELECT itemprice(
666 {$itemsite->itemsite_item_id},
669 {$row->invhist_transfer_item_qty},
675 if ( empty($ipsass->result) || $ipsass->result == 0.0) {
676 $bad_items[] = $itemsite->itemsite_item_id;
680 $priceLists[$row->invhist_transfer_item_itemsite_id] = $ipsass->result;
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));
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);
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 ;
709 $roo->jerr("invalid price type: ". $this->invhist_transfer_price);
712 // print_R($priceLists);exit;
717 $adt = date('Y-m-d', strtotime($this->invhist_transfer_arrivaldate));
718 $bad_items = array();
719 foreach($allItems as $rn => $row)
722 if (empty($priceLists[$row->invhist_transfer_item_itemsite_id])) {
723 $bad_items[] = $row->item_number;
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,
739 if (!empty($bad_items)) {
740 $roo->jerr("no prices for ". implode(', ', $bad_items));
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);
749 //$roo->jok("an invoice should have been created");
750 //$roo->jerr("testing");
751 $this->createRemotePO($roo,$target_office, $items);
753 $roo->sessionState(1); // unless jok does sesson stuff may not need to start session again..
754 // flag this as posted..
756 $items = $this->items();
757 foreach ($items as $item){
759 $item->invhist_transfer_item_unit_price_default = $i->invhist_transfer_item_unit_price;
764 $this->invhist_transfer_posted = true;
769 $roo->addEvent("POSTED", $this);
770 $roo->jok("CREATED");
777 function createRemotePO($roo,$target_office, $items )
779 $target_office = strtolower($target_office);
781 $lt = $this->location_to();
784 * check that the target location is actually a local location
787 $ourdb = substr($this->database(), -2);
788 if ($target_office == $ourdb) {
789 $roo->jerr("target office matches our office?");
792 $cust = $lt->customer();
795 $roo->jerr("could not find customer");
798 $cur = $cust->priceListCurrency($roo);
800 $po_prefix = 'XF-'. strtoupper(substr($this->database(),-2)).'-'. strtoupper($target_office) .'-';
803 $url = 'http://localhost'.HTML_FlexyFramework::get()->page->rootURL .'/'. $target_office .'.php';
804 // $roo->jerr("posting to $url");
806 $dt = date('Y-m-d', strtotime($this->invhist_transfer_transdate));
808 require_once 'HTTP/Request.php';
810 $req = new HTTP_Request( $url . '/Roo/Pohead' );
811 $req->setMethod(HTTP_REQUEST_METHOD_POST);
812 $req->addPostData( array(
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,
818 'pohead_released' => $dt,
819 //'invchead_invcdate' => $this->shiphead_shipdate,
820 '_vendor_internal_company' => substr($this->database(),-2) ,
821 'curr_name' => $cur->curr_name,
823 'items' => json_encode($items),
824 'target_location' => $lt->location_name
827 //$roo->jerr( print_r($req->_postData,true));
828 //$roo->jerr( $req->_url->getURL() );
830 $res = $req->sendRequest();
832 if (is_a($res,'PEAR_Error')) {
833 $roo->jerr("REMOTE REQUEST RETURNED: ". $res->toString());
835 $res = json_decode($req->getResponseBody());
837 if (!is_object($res)) {
838 $roo->jerr("REMOTE REQUEST RETURNED: ". $req->getResponseBody());
841 if (!$res->success) {
842 $roo->jerr("REMOTE REQUEST RETURNED: ". $res->errorMsg);
845 return (array) $res->data;
848 function createLocalInvoice($roo, $target_office, $items)
851 $invc = DB_DataObject::Factory('invchead');
852 $invc->createFromTransfer($roo, $target_office, $this, $items);
859 function createFromRecvGroup($roo, $rg)
865 $new = $this->factory($this->tableName());
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()
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;
880 $new->updateItems($up, $roo);
886 function checkLocationStock($roo)
888 if(empty($roo->bootLoader->Xtuple['prevent_negative'])){
892 $items = $this->items();
896 foreach ($items as $item){
897 if(empty($item->invhist_transfer_item_qty)){
901 $balance = $item->itemsite()->checkLocationStock($this->invhist_transfer_from);
903 if(empty($balance) || $balance < $item->invhist_transfer_item_qty){
904 $stock[] = $item->itemsite()->item()->item_number;
909 $roo->jerr("These items have negative stock " . implode(', ', $stock));
915 $copy = $this->toArray();
917 $t = DB_DataObject::factory('invhist_transfer');
920 'invhist_transfer_id' => 0,
921 'invhist_transfer_posted' => false,
922 'invhist_transfer_void' => false,
923 'invhist_transfer_number' => $t->generateNumber()
928 $i = DB_DataObject::factory('invhist_transfer_item');
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
937 $i->invhist_transfer_item_invhist_transfer_id = $this->pid();
938 $items = $i->fetchAll();
940 $t->updateItems($items, $roo);
944 function fixTransfer($roo)
946 $invdetail = DB_DataObject::factory('invfifo');
954 invfifo_invdetail_id IN (
960 invhist_comments = '{$this->invhist_transfer_number}'
962 invhist_comments = '{$this->invhist_transfer_number}' || ' REVERSED'
967 $invdetail = DB_DataObject::factory('invdetail');
971 invfifo_update_from_invdetail(invdetail_id, TRUE)
975 invhist_comments = '{$this->invhist_transfer_number}'
977 invhist_comments = '{$this->invhist_transfer_number}' || ' REVERSED'