<?php
/**
 * Created by JetBrains PhpStorm.
 * User: user
 * Date: 15-6-3
 * Time: 下午2:54
 * To change this template use File | Settings | File Templates.
 */
class Service_SwapOrderProcess
{
    protected $_warehouseId;
    protected $_date;
    protected $_picking;
    protected $_isAbnormal = 0;//是否是异常易货单，0不是 1是
    protected $_fromProducts = array();//保存来源产品
    protected $_toProducts = array();//保存目标产品
    protected $_data;//传进来的数据
    protected $_order;//易货单
    protected $_customers = array();
    protected $_hasQc = false;
    protected $_ip;

    public function createTransaction($data){
        $result = array('ask' => 0, 'message' => '', 'error' => array(), 'swo_code' => '');

        $this->_date = date('Y-m-d H:i:s');
        $this->_warehouseId = 1;
        $this->_isAbnormal = isset( $data['isAbnormal'] ) && $data['isAbnormal'] == 1 ? 1 : 0;
        $this->_ip = Common_Common::getIP();
        
        $error = $this->validate($data);
        if(!empty($error)){
            $result['error'] = $error;
            return $result;
        }
        $DB = Common_Common::getAdapter();
        $DB->beginTransaction();
        try{

            $this->_customers[ $data['customer_code'] ] = Service_Customer::getByField( $data['customer_code'], 'customer_code');

            //添加主表数据
            $this->addOrder();
            if( $this->_isAbnormal == 1 ) {
                $this->addPicking();
            }

            foreach($data['swapOrderDetail'] as $key=>$value){
                //添加明细表
                $id = $this->addOrderDetail( $value );
                //冻结总库存
                $this->frozenInventory( $value );
                //异常易货单冻结批次库存
                if( $this->_isAbnormal == 1 ) {
                    $this->offShelf( $value, $id );
                }
            }
            $DB->commit();
            $result['ask']='1';
            $result['message'] = '易货单['.$this->_order['swo_code'].']创建成功.'; //'ASN创建成功';
            $result['swo_code'] = $this->_order['swo_code'];
        }catch (Exception $e){
            $DB->rollBack();
            $result['error'][] = $e->getMessage();
            $result['message'] = '创建易货单失败';
        }
        return $result;
    }

    protected function addOrder() {
        $swo_code = self::createCode();
        $this->_order = array(
            'swo_code'              => $swo_code,
            'customer_id'           => $this->_data['customer_id'],
            'customer_code'         => $this->_data['customer_code'],
            'serial_code'           => $this->_data['serial_code'],
            'remark'                 => $this->_data['remark'],
            'warehouse_id'          => $this->_warehouseId,
            'swo_status'            => $this->_isAbnormal == 1 ? 3 : 2,
            'add_time'               => $this->_date,
            'last_update_time'      => $this->_date,
            'has_customer_qc'       => $this->_hasQc ? 1 : 0,
            'is_abnormal'            => $this->_isAbnormal
        );
        $id = Service_SwapOrder::add( $this->_order );
        $this->_order['swo_id'] = $id;
    }

    protected function addOrderDetail( $detail ) {
        $existFromProduct = $this->_fromProducts[ $detail['from_customer_code'] ][ $detail['from_sku'] ];

        if( !isset( $this->_toProducts[$detail['to_sku']] ) ){
            $this->addProduct( $detail );
        }

        $swapOrderDetail = array(
            'swo_code'                  => $this->_order['swo_code'],
            'swo_id'                    => $this->_order['swo_id'],
            'from_customer_code'      => $detail['from_customer_code'],
            'product_id'               => $existFromProduct['product_id'],
            'quantity'                  => $detail['quantity'],
            'from_sku'                  => $detail['from_sku'],
            'to_sku'                    => $detail['to_sku'],
            'to_product_barcode'      => $detail['to_product_barcode'],
            'sod_remark'               => $detail['sod_remark'],
            'add_time'                  => $this->_date,
            'swod_status'               => $this->_isAbnormal == 0 ? 2 : 3,
            'last_update_time'         => $this->_date,
            'is_qc'                      => isset($detail['is_qc']) ? $detail['is_qc'] : "0",
            'qc_subject'                => isset($detail['qc_subject']) ? $detail['qc_subject'] : "",
            'qc_category'               => isset($detail['qc_category']) ? $detail['qc_category'] : "",
            'qc_quantity'               => isset($detail['qc_quantity']) ? $detail['qc_quantity'] : "0",
            'is_package'                => isset($detail['is_package']) ? $detail['is_package'] : "0",
            'to_product_id'             => $this->_toProducts[$detail['to_sku']]['product_id']
        );
        $id = Service_SwapOrderDetail::add($swapOrderDetail);
        if( !$id ) throw new Exception( '添加易货单明细失败' );

        return $id;
    }

    protected function addProduct( $detail ) {
        $existFromProduct = $this->_fromProducts[ $detail['from_customer_code'] ][ $detail['from_sku'] ];

        $newProduct = $existFromProduct;
        $newProduct['customer_code'] = $this->_data['customer_code'];
        $newProduct['product_sku'] = $detail['to_sku'];
        $newProduct['customer_id'] = $this->_data['customer_id'];
        $newProduct['product_barcode'] = $detail['to_product_barcode'];

        $fromProductId = $newProduct['product_id'];
        unset($newProduct['product_id']);

        $pid = Service_Product::add( $newProduct );
        if( !$pid ) throw new Exception('创建新产品失败');

        $newProduct['product_id'] = $pid;

        /*$productGood = Service_ProductGoods::getByField($fromProductId,'product_id',"*");
        if(!empty($productGood)){
            $newProductGood = $productGood;
            unset($newProductGood['pg_id']);
            $newProductGood['product_id'] = $pid;
            Service_ProductGoods::add($newProductGood);
        }*/
        $hsElementMap = Service_HsElementMap::getByCondition(array('product_id'=>$fromProductId),"*");
        if(!empty($hsElementMap)){
            foreach($hsElementMap as $hem){
                unset($hem['hem_id']);
                $hem['product_id'] = $pid;
                $id = Service_HsElementMap::add($hem);
                if( !$id ) throw new Exception('添加ToSKU:'.$detail['to_sku'].'的海关申报要素失败');
            }
        }
        $hsUomMap = Service_HsUomMap::getByField($fromProductId,'product_id',"*");
        if(!empty($hsUomMap)){
            unset($hsUomMap['hum_id']);
            $hsUomMap['product_id'] = $pid;
            $id = Service_HsUomMap::add($hsUomMap);
            if( !$id ) throw new Exception('添加ToSKU:'.$detail['to_sku'].'的法定单位失败');
        }
        $this->_toProducts[ $detail['to_sku'] ] = $newProduct;
    }

    protected function frozenInventory( $detail ) {

        $existFromProduct = $this->_fromProducts[$detail['from_customer_code']][ $detail['from_sku'] ];

        $conInventory = array(
            'product_id'   => $existFromProduct['product_id'],
            'warehouse_id' => $this->_warehouseId
        );

        $productInventory = Service_ProductInventory::getByCondition($conInventory,"*",0,1,'',"for update");
        if( empty( $productInventory ) ) throw new Exception( '用户:'.$detail['from_customer_code'].',SKU:'.$detail['from_sku'].'无库存' );

        $inventory = $productInventory[0];

        if( $inventory['pi_sellable'] - $detail['quantity'] < 0 )
            throw new Exception( '用户:'.$detail['from_customer_code'].',SKU:'.$detail['from_sku'].'可用库存只有'.$inventory['pi_sellable'] );

        //修改product_inventory 记录
        $productInventoryRow = array(
            'pi_sellable' => $inventory['pi_sellable'] - $detail['quantity'],
            'pi_reserved' => $inventory['pi_reserved'] + $detail['quantity'],
            'pi_update_time' => $this->_date
        );
        $result = Service_ProductInventory::update($productInventoryRow, $inventory['pi_id']);
        if( !$result )
            throw new Exception(  '用户:'.$detail['from_customer_code'].',SKU:'.$detail['from_sku'].'更新库存失败' );

        $productInventoryLogRow = array(
            'product_id'                    => $inventory['product_id'],
            'product_barcode'              => $inventory['product_barcode'],
            'warehouse_id'                 => $this->_warehouseId,
            'user_id'                       => '-1',
            'pil_sellable'                 => $inventory['pi_sellable']- $detail['quantity'],
            'pil_reserved'                 => $inventory['pi_reserved']+ $detail['quantity'],
            'pil_onway'                    => $inventory['pi_onway'],
            'pil_pending'                  => $inventory['pi_pending'],
            'pil_unsellable'              => $inventory['pi_unsellable'],
            'pil_shipped'                 => $inventory['pi_shipped'],
            'pil_ip'                       => Common_Common::getIP(),
            'pil_add_time'                => $this->_date,
            'pil_note'                     => '易货单新建',
            'from_it_code'                => 'Confirm',
            'to_it_code'                  => 'Submitted',
            'reference_code'             => $this->_order['swo_code'],
            'pil_quantity'               => $detail['quantity'],
        );
        $result = Service_ProductInventoryLog::add($productInventoryLogRow);
        if( !$result )
            throw new Exception( '用户:'.$detail['from_customer_code'].',SKU:'.$detail['from_sku'].'记录日志失败' );
    }

    public function createCode()
    {
        if ($this->_pro == '') {
            //$this->_pro = 'RE';
            $this->_pro = 'SWO';
        }
        $this->_pro = strtoupper($this->_pro);
        //return Common_GetNumbers::getCode('ASN', '', $this->_pro);
        return Common_GetNumbers::getOnlyCode('SWOOnly', '', $this->_pro);
    }

    protected  function validate($data){
        $error = array();
        if (empty($data)) {
            $error[]=Ec_Lang::getInstance()->getTranslate('DataError');//'数据出错';
            return $error;
        }
        foreach($data['swapOrderDetail'] as $key=>$value){
            $customer = Service_Customer::getByField($value['from_customer_code'],'customer_code',"*");
            if(empty($customer)){
                $error[] = "客户代码[".$value['from_customer_code']."]不存在";
            } else {
                $this->_customers[ $value['from_customer_code'] ] = $customer;
            }
            $condition = array(
                'customer_code'=>$value['from_customer_code'],
                'product_sku'=>$value['from_sku'],
            );
            $existFromProduct = Service_Product::getByCondition($condition,'*');
            if(empty($existFromProduct)){
                $error[] = "客户代码[".$value['from_customer_code']."]不存在产品[".$value['from_sku']."]";
            }else{
                if( !isset( $this->_fromProducts[$value['from_customer_code']] ) )
                    $this->_fromProducts[$value['from_customer_code']] = array();

                //SKU要按客户区分，可能来源于不同的客户，不同客户可能SKU相同
                $this->_fromProducts[$value['from_customer_code']][ $value['from_sku'] ] = $existFromProduct[0];

                if($existFromProduct[0]['product_status']!="1"){
                    $error[] = "产品[".$value['from_sku']."]未备案";
                }else{
                    $condition2 = array(
                        'customer_code'=>$data['customer_code'],
                        'product_sku'=>$value['to_sku'],
                    );
                    $exstToProduct = Service_Product::getByCondition($condition2,"*");
                    if(!empty($exstToProduct)){
                        //SKU无须按客户区分，因为是易货给一个客户
                        $this->_toProducts[ $value['to_sku'] ] = $exstToProduct[0];
                        //暂时限制正常易货必须相同料件号，异常易货不限制
                        if( $this->_isAbnormal == 0 && $exstToProduct[0]['goods_id']!=$existFromProduct[0]['goods_id']){
                            $error[] = "toSKU的料件号[".$exstToProduct[0]['goods_id']."]与FromSKU的料件号[".$existFromProduct[0]['goods_id']."]不一致";
                        }
                        if($exstToProduct[0]['product_barcode']!=$value['to_product_barcode']){
                            $error[] = "现有产品的sku[".$exstToProduct[0]['product_sku']."]的产品条码[".$exstToProduct[0]['product_barcode']."]与目的产品条码[".$value['to_product_barcode']."]不一致";
                        }
                    }
                }
            }
            if($value["is_qc"]=="1"){
                if($value['qc_subject']==""){
                    $error[]="产品[".$value['from_sku']."]质检主体必填";
                }
                if($value['qc_subject']=="BH"){
                    if($value['qc_category']==""){
                        $error[]="产品[".$value['from_sku']."]质检类别必填";
                    }else{
                        $exitQcc = Service_QcCategory::getByField($value['qc_category'],'qcc_code');
                        if(empty($exitQcc)){
                            $error[]="产品[".$value['from_sku']."]质检类别不存在";
                        }
                    }
                } else {
                    $this->_hasQc = true;
                }
                if($value['qc_quantity']==""){
                    $error[]="产品[".$value['from_sku']."]质检数量必填";
                }
            }
        }
        $this->_data = $data;
        return $error;
    }

    public function offShelf( $detail, $detailId ){

        $product = $this->_fromProducts[ $detail['from_customer_code'] ][ $detail['from_sku'] ];
        $toProduct = $this->_toProducts[ $detail['to_sku'] ];
        $condition = array(
            'product_id' => $product['product_id'],
            'warehouse_id' => $this->_warehouseId,
            'from_product_id' => $toProduct['product_id'],
            'ib_status' => 1,
            'ib_hold_status' => 0,
        );
        $batches = Service_InventoryBatch::getByCondition( $condition, '*', 0, 0, 'ib_id asc'); //先进先出
        if ( empty( $batches ) )
            throw new Exception( '用户:'.$detail['from_customer_code'].',SKU:'.$detail['from_sku'].'批次库存不足');

        $orderQty = $detail['quantity'];

        foreach ( $batches as $batch) {
            $condition = array(
                'ib_id' => $batch['ib_id'],
            );
            $sumQty = Service_InventoryBatchOutbound::getByCondition( $condition, 'sum(ibo_quantity) as sum_qty');

            $availableQty = $batch['ib_quantity'] - $sumQty[0]['sum_qty'];

            $orderQty = $orderQty - $availableQty;
            $deductQty = $orderQty >= 0 ? $availableQty : $availableQty + $orderQty;

            //添加出库核销记录
            $iboId = $this->addOutbound( $batch, $deductQty );
            //添加下架单明细
            $this->addPickingDetail( $batch, $iboId, $deductQty, $detailId );
            //添加批次库存日志
            $this->addInventoryBatchLog( $batch, $availableQty );

            //如果数量大于0，说明批次库存足够扣
            if( $orderQty <= 0 ) {
                break;
            }
        }

        if ( $orderQty > 0 )
            throw new Exception( '用户:'.$detail['from_customer_code'].',SKU:'.$detail['from_sku'].'库存不足');
    }

    protected function addPicking() {
        $pickCode = Common_GetNumbers::getCode('picking', $this->_warehouseId, 'PL'); // 配货号
        $this->_picking = array(
            'warehouse_id'                              => $this->_warehouseId,
            'picking_code'                              => $pickCode,
            'picker_id'                                  => 0,
            'creater_id'                                 => 0,
            'picking_order_cnt'                         => '0',
            'picking_lc_cnt'                            => '0',
            'picking_item_cnt'                          => '0',
            'picking_status'                            => '0',
            'is_assign'                                  => 0,
            'picking_type'                              => '1',
            'picking_add_time'                         => $this->_date,
            'picking_update_time'                      => $this->_date,
            'picking_model'                             => '1',
        );
        if (!$id = Service_Picking::add( $this->_picking ) ) {
            throw new Exception( '生成下架单失败' );
        }
        $this->_picking['picking_id'] = $id;
    }

    protected function addOutbound( $batch, $deductQty) {
        // 插入一条产品出库核销记录
        $boundRow = array(
            'lc_code'            => $batch['lc_code'],
            'warehouse_id'      => $this->_warehouseId,
            'reference_no'      => $this->_order['swo_code'],
            'application_code' => 'pickup',
            'ibo_quantity'      => $deductQty,
            'ib_id'              => $batch['ib_id'],
            'ibo_add_time'      => $this->_date
        );
        if (!$id = Service_InventoryBatchOutbound::add( $boundRow ) ) {
            throw new Exception( '冻结库存失败' );
        }

        $boundLogRow = array(
            'lc_code'                   => $batch['lc_code'],
            'ibo_id'                    => $id,
            'ib_id'                     => $batch['ib_id'],
            'reference_no'             => $this->_order['swo_code'],
            'application_code'        => 'pickup',
            'ibol_quantity'            => $deductQty,
            'user_id'                   => '0',
            'ibol_ip'                   => $this->_ip,
            'ibol_add_time'            => $this->_date,
            'ibol_note'                 => $batch['product_barcode']
        );
        if ( !Service_InventoryBatchOutboundLog::add( $boundLogRow ) )
            throw new Exception( '冻结库存失败' );

        return $id;
    }


    protected function addPickingDetail( $batch, $iboId, $deductQty, $detailId) {
        $pickingDetailRow = array(
            'picking_id'                    => $this->_picking['picking_id'],
            'picking_code'                  => $this->_picking['picking_code'],
            'order_id'                       => $this->_order['swo_id'],
            'order_code'                     => $this->_order['swo_code'],
            'pd_status'                      => '0',
            'op_id'                           => $detailId,
            'pd_quantity'                    => $deductQty,
            'ibo_id'                          => $iboId,
            'product_id'                     => $batch['product_id'],
            'product_barcode'               => $batch['product_barcode'],
            'ib_id'                           => $batch['ib_id'],
            'lc_code'                         => $batch['lc_code'],
            'pd_add_time'                    => $this->_date
        );
        $id = Service_PickingDetail::add( $pickingDetailRow );
        if ( !$id )
            throw new Exception( '生成下架数据失败' );
    }

    protected function addInventoryBatchLog( $batch, $availableQty ) {
        $batchLog = array(
            'lc_code'                       => $batch['lc_code'],
            'product_id'                   => $batch['product_id'],
            'product_barcode'             => $batch['product_barcode'],
            'supplier_id'                  => '',
            'warehouse_id'                 => $this->_warehouseId,
            'ib_id'                         => $batch['ib_id'],
            'receiving_code'               => '',
            'reference_no'                 => $this->_order['swo_code'],
            'application_code'            => '',
            'ibl_note'                     => $batch['product_barcode'],
            'ibl_quantity_before'        => $availableQty,
            'ibl_quantity_after'         => $availableQty,
            'user_id'                      => '0',
            'ibl_ip'                       => $this->_ip,
            'ibl_add_time'                => $this->_date
        );

        if (!Service_InventoryBatchLog::add($batchLog))
            throw new Exception('记录库存日志失败');
    }



}
