pairs = $set ? array_merge($set->pairs) : array(); } function add($value, $field, $quote=true) { if($value !=null) { array_push($this->pairs, $quote ? "$field = '$value'" : "$field = $value"); } return $this; } function addDate($date, $field) { return $this->add(date2sql($date), $field); } function toString() { return implode(', ', $this->pairs); } } class Split { public $start_date; public $end_date; public $quantity=0; public $quantity_dispatched=0; function __construct($start_date, $period=null) { $this->start_date = $start_date; $this->end_date = $start_date; if($period) $this->extend($period); } function extend($days) { $this->end_date = add_days($this->end_date, $days); } } class Splitter { public $detail_ids = array() ; public $start_date; public $end_date; protected $days; public $max_quantity; public function __construct(array $data) { $this->detail_ids = array(); foreach($data['detail'] as $detail_id => $detail) { array_push($this->detail_ids, $detail_id); } $this->start_date = $data['start_date']; $this->end_date = $data['end_date']; $this->days = date_diff2($this->end_date, $this->start_date, 'd'); $this->max_quantity = $data['max_quantity']; } protected function loadDetail($detail_id) { $sql = "SELECT * FROM ".TB_PREF."sales_order_details WHERE id = $detail_id"; $result = db_query($sql); return db_fetch($result); } public function splitAll() { $ok = true; foreach($this->detail_ids as $detail_id) { display_warning("processing $detail_id"); $detail = $this->loadDetail($detail_id); $splits = $this->split($detail); $ok &= $this->saveSplits($detail, $splits); } return $ok; } public function days() { return $this->days; } /* This function splits on order detail in bits of a specified size. * Each split starting at the end time of the previous one. * the first split starts at the start_date and ends at the end_date. * The 'splitting' split the whole quantity not only the quantity left to dispatch * However, fully dispatched split won't be split in real, but merged with the next one */ public function split($row) { $splits = array(); $quantity = $row['quantity']; $quantity_sent = $row['qty_sent']; /* Check if the item has been fully dispatched. * If so, there is no need to do anything. */ if($quantity_sent >= $quantity) return $splits; // determine the number of split needed. This will give us the lenght of a split. $nsplit = ceil($quantity/$this->max_quantity); $period = $this->days/$nsplit; array_push($splits, $split = new Split($this->start_date, $period)); $split->quantity_dispatched = $quantity_sent; $split_quantity = min($quantity, $this->max_quantity); while($split_quantity > 0) { $split->quantity += $split_quantity; // Check if the split has been entirely dispatch or not. if($split->quantity_dispatched > $split->quantity) { //extend the split $split->extend($period); } else { // create a new split array_push($splits, $split = new Split($split->end_date, $period)); } $quantity -= $split_quantity; $split_quantity = min($quantity, $this->max_quantity); } // We need to remove the last split if it's empty if($split->quantity == 0) array_pop($splits); return $splits; } public function saveSplits($detail, $splits) { if(empty($splits)) return true; $detail_id = $detail['id']; $priority = $detail['priority']; $order_no = $detail['order_no']; $trans_type = $detail['trans_type']; /* We need to update the first one (as it exists already in the database) * but insert the following one. */ $first = array_shift($splits); $set = new SqlSet(); $set->addDate($first->start_date, 'hold_until_date') ->addDate($first->end_date, 'expiry_date') ->add($first->quantity, 'quantity', false) ->add($priority, 'priority'); display_warning($set->toString()); db_query("UPDATE ".TB_PREF."sales_order_details SET {$set->toString()} WHERE id = $detail_id", "Problem splitting order details $detail_id"); // Compute common field for each split $common_set = new SqlSet(); $common_set->add($order_no, 'order_no', false) ->add($priority, 'priority') ->add($trans_type, 'trans_type') ->add($detail['required_date'], 'required_date') ->add($detail['comment'], 'comment') ->add($detail['stk_code'], 'stk_code') ->add($detail['description'], 'description') ->add($detail['unit_price'], 'unit_price', false) ->add($detail['discount_percent'], 'discount_percent', false); foreach($splits as $split) { $set = new SqlSet($common_set); $set->addDate($split->start_date, 'hold_until_date') ->addDate($split->end_date, 'expiry_date') ->add($split->quantity, 'quantity', false); display_warning($set->toString()); db_query("INSERT INTO ".TB_PREF."sales_order_details SET {$set->toString()}" ,"Problem spliting order details $detail_id"); } return true; } } ?>