BulkUpdater work.
[order_line_extra.git] / includes / splitter.inc
1 <?php
2 require_once('includes/sql_set.inc');
3
4 class Split {
5         public $start_date;
6         public $end_date;
7         public $quantity=0;
8         public $quantity_dispatched=0;
9         
10
11         function __construct($start_date, $period=null) {
12                         $this->start_date = $start_date;
13                         $this->end_date = $start_date;
14                         if($period) $this->extend($period);
15         }
16
17         function extend($days) {
18                         $this->end_date = add_days($this->end_date, $days);
19         }
20 }
21
22 class Splitter extends OrderAction {
23         public $start_date;
24         public $end_date;
25         public $start_offset;
26         public $end_offset;
27         protected $days;
28         public $max_quantity;
29
30         public function __construct(array $data) {
31                 parent::__construct($data);
32                 $this->start_date = $data['start_date'];
33                 $this->end_date = $data['end_date'];
34                 $this->start_offset = $data['start_offset'];
35                 $this->end_offset = $data['end_offset'];
36                 $this->days = date_diff2($this->end_date, $this->start_date, 'd');
37
38                 $this->max_quantity = $data['max_quantity'];
39         }
40
41         protected function loadDetail($detail_id) {
42                 $sql = "SELECT *
43                                                 FROM ".TB_PREF."sales_order_details
44                                                 WHERE id = $detail_id";
45                 $result = db_query($sql);
46                 return db_fetch($result);
47         }
48
49         public function splitAll() {
50                 $ok =  true;
51                 foreach($this->detail_ids as $detail_id) {
52 display_warning("processing $detail_id");
53                                 $detail = $this->loadDetail($detail_id);
54                                 $splits = $this->split($detail);
55                                 foreach($splits as $split) $this->alterSplit($split);
56                                 $ok &= $this->saveSplits($detail, $splits);
57                 }
58
59                 return $ok; 
60         }
61
62         public function days() {
63                 return $this->days;
64         }
65
66
67         
68         /* This function splits on order detail in bits of a specified size.
69  * Each split  starting at the end time of the previous one.
70  * the first split starts at the start_date and ends at the end_date.
71  * The 'splitting' split the whole quantity not only the quantity left to dispatch
72  * However, fully dispatched split won't be split in real, but merged with the next one
73  */
74         public function split($row) {
75                 $splits = array();
76                 $quantity = $row['quantity'];
77                 $quantity_sent = $row['qty_sent'];
78
79                 /* Check if the item has been fully dispatched.
80                  * If so,  there is no need to do anything.
81                  */
82                 if($quantity_sent >= $quantity) return $splits;
83                 
84                 // determine the number of split needed. This will give us the lenght of a split.
85                 $nsplit = ceil($quantity/$this->max_quantity);
86
87                 $period = $this->days/$nsplit;
88
89                 array_push($splits, $split = new Split($this->start_date, $period));
90                 $split->quantity_dispatched = $quantity_sent;
91                 $split_quantity = min($quantity, $this->max_quantity);
92                 while($split_quantity > 0) {
93                                         $split->quantity += $split_quantity;
94                                 // Check if the split has been entirely dispatch or not.
95                                 if($split->quantity_dispatched > $split->quantity) {
96                                         //extend the split
97                                         $split->extend($period);
98                                 }
99                                 else {
100                                         // create a new split
101                                         array_push($splits, $split = new Split($split->end_date, $period));
102                                         
103                                 }
104                                 $quantity -= $split_quantity;
105                                 $split_quantity = min($quantity, $this->max_quantity);
106                 }
107
108                 // We need to remove the last split if it's empty
109                 if($split->quantity == 0) array_pop($splits);
110                 return $splits;
111         }
112
113         function alterSplit($split) {
114                 foreach(explode(' ', 'start end') as $att) {
115                         $date = "${att}_date";
116                         $offset = "${att}_offset";
117                         if($this->$offset === null || $this->$offset === "") {
118                                 $split->$date = null;
119                         }
120                         else {
121                                 $split->$date = add_days($split->$date, $this->$offset);
122                         }
123                 }
124         }
125
126         public function saveSplits($detail, $splits) {
127                 if(empty($splits)) return true;
128
129                 $detail_id = $detail['id'];
130                 $priority = $detail['priority'];
131                 $priority_offset = 1;
132                 $order_no = $detail['order_no'];
133                 $trans_type = $detail['trans_type'];
134
135                 /* We need to update the first one (as it exists already in the database)
136                  * but insert the following one.
137                  */
138                 $first = array_shift($splits);
139                 $set = new SqlSet();
140                 $set->addDate($first->start_date, 'hold_until_date')
141                                 ->addDate($first->end_date, 'expiry_date')
142                                 ->add($first->quantity, 'quantity', false);
143         display_warning($set->toString());
144                 db_query("UPDATE ".TB_PREF."sales_order_details
145                                                         SET {$set->toString()}
146                                                         WHERE id = $detail_id", "Problem splitting order details $detail_id");
147
148                 // Compute common field for each split
149                 $common_set  = new SqlSet();
150                 $common_set->add($order_no, 'order_no', false)
151                                 ->add($trans_type, 'trans_type')
152                                 ->add($detail['required_date'], 'required_date')
153                                 ->add($detail['comment'], 'comment')
154                                 ->add($detail['stk_code'], 'stk_code')
155                                 ->add($detail['description'], 'description')
156                                 ->add($detail['unit_price'], 'unit_price', false)
157                                 ->add($detail['discount_percent'], 'discount_percent', false);
158
159                 foreach($splits as $split) {
160                         $set = new SqlSet($common_set);
161                         $set->addDate($split->start_date, 'hold_until_date')
162                                 ->addDate($split->end_date, 'expiry_date')
163                                 ->add($split->quantity, 'quantity', false);
164         display_warning($set->toString());
165                 db_query("INSERT INTO ".TB_PREF."sales_order_details
166                                                         SET {$set->toString()}
167                                                         , priority = '$priority' + INTERVAL ${priority_offset} second"
168                                                  ,"Problem spliting order details $detail_id");
169                                 $priority_offset++;
170                 }
171
172                 return true;
173                 
174
175         }
176
177 }
178 ?>