Maestro-Detalle / Factura Compra en Yii – Parte I

| 2014-01-16 | No hay comentarios »

fac-compraQuiero seguir con mis tutoriales de Yii framework en este 2014, ésta vez quiero dar comienzo al manual intermedio con este tema que es bastante complejo de entender. Hago este tutorial ya que me han pedido varias personas, espero que les sea de gran utilidad, se puede mejorar mucho el código y hacer muchas optimizaciones!!!!

Antes de comenzar les dejo el source code del proyecto completo de Yii con el .sql de la base de datos (Se encuentra dentro del proyecto, en la carpeta Base de datos):

github-logo

Si tienen alguna duda, no duden en hacérmela.

Lo primero que necesitan de saber es como guardar los datos al estar creando una factura (ya sea de la cabecera y también de los detalles), yo por mi parte opté la utilización de sesiones, cree una clase especial solo para los seters y geters: (Compra.php ubicado en la carpeta models)


<?php
 class Compra
 {

public static function getContenidoCompra() {
 if(is_string(Yii::app()->user->getState('compra')))
 return CJSON::decode(Yii::app()->user->getState('compra'), true);
 else
 return Yii::app()->user->getState('compra');
 }

public static function setContenidoCompra($compra) {
 return Yii::app()->user->setState('compra', CJSON::encode($compra));
 }

 public static function setContenidoCheque($cheque) {
 return Yii::app()->user->setState('cheque', CJSON::encode($cheque));
 }

 public static function getContenidoCheque() {
 if(is_string(Yii::app()->user->getState('cheque')))
 return CJSON::decode(Yii::app()->user->getState('cheque'), true);
 else
 return Yii::app()->user->getState('cheque');
 }

 public static function getProveedor() {
 return Yii::app()->user->getState('proveedor');
 }

public static function setProveedor($proveedor) {
 return Yii::app()->user->setState('proveedor', $proveedor);
 }

 public static function getPago() {
 return Yii::app()->user->getState('pagoc');
 }

public static function setPago($pagoc) {
 return Yii::app()->user->setState('pagoc', $pagoc);
 }

 public static function getDoc() {
 return Yii::app()->user->getState('doc');
 }

public static function setDoc($doc) {
 return Yii::app()->user->setState('doc', $doc);
 }

public static function getTotal($par=false) {
 $total=$iva=$dcto=0;
 if(@$compra=Compra::getContenidoCompra())
 foreach($compra as $product) {
 //$model=Productos::model()->findByPk($product['id_producto']);
 //$resultado=ProductoProveedor::getProductoProveedor($model->id_producto);
 //$subtotal+=@$product['cantidad']*@$product['precio'];
 //$dcto+=(@$product['cantidad']*@$product['precio']*@$product['dcto'])/100;
 //$iva+=(((@$product['cantidad']*@$product['precio'])-((@$product['cantidad']*@$product['precio']*@$product['dcto'])/100))*@$product['iva'])/100;
 $precio=(@$product['precio']-((@$product['precio']*@$product['dcto'])/100))*@$product['cantidad'];
 $dcto+=((@$product['precio']*@$product['dcto'])/100)*@$product['cantidad'];
 $per=1+(@$product['iva']/100);
 $iva+=(float)($precio-($precio/$per));
 $total+=$precio;
 }
 if($par==true) return array(
 //'subtotal'=>$subtotal,
 'dcto'=>$dcto,
 'iva'=>$iva,
 'total'=>$total
 );
 else
 return ' <div class="resumen">
 <h3>RESUMEN</h3>
 <table class="table">
 <tbody>
 <tr>
 <td class="detail-view">
 <table>
 <tr>
 <th>TOTAL DESCUENTO:</th>
 <td class="textright iva">'.$dcto.'</td>
 </tr>
 <tr>
 <th>TOTAL IVA:</th>
 <td class="textright iva"><span>'.$iva.'</span></td>
 </tr>
 <tr>
 <th>TOTAL A PAGAR:</th>
 <td class="textright totalgral"><span>'.$total.'</span></td>
 </tr>
 </table>
 </td>
 </tr>
 </tbody>
 </table>
 </div>';
 }

 }

Modelo CabCompra.php (ubicado en la carpeta models): No quiero entrar en detalles de todas las cosas que poseen los siguientes modelos ya que lo mejor sería que utilicen lo que les sirva, no hagan copy/paste solamente.


<?php

/**
 * This is the model class for table "cab_compra".
 *
 * The followings are the available columns in table 'cab_compra':
 * @property string $id_compra
 * @property string $id_proveedor
 * @property string $nro_documento
 * @property string $fecha_compra
 * @property string $fecha_registro
 * @property string $estado
 * @property string $user
 * @property integer $id_tipo_documento
 * @property double $sub_total
 * @property double $igv
 * @property double $total
 * @property string $estado_pago
 * @property string $obs
 * @property string $id_tipo_pago
 * @property double $descuento_total
 *
 * The followings are the available model relations:
 * @property TiposDocumentos $idTipoDocumento
 * @property TiposPago $idTipoPago
 * @property Proveedores $idProveedor
 */
class CabCompra extends CActiveRecord
{

public $id_producto;
 public $date_first;
 public $date_last;
 public $date_first2;
 public $date_last2;
 /**
 * Returns the static model of the specified AR class.
 * @param string $className active record class name.
 * @return CabCompra the static model class
 */
 public static function model($className=__CLASS__)
 {
 return parent::model($className);
 }

/**
 * @return string the associated database table name
 */
 public function tableName()
 {
 return 'cab_compra';
 }

/**
 * @return array validation rules for model attributes.
 */
 public function rules()
 {
 // NOTE: you should only define rules for those attributes that
 // will receive user inputs.
 return array(
 array('id_proveedor, fecha_compra, user, id_tipo_documento, total', 'required'),
 array('id_tipo_documento', 'numerical', 'integerOnly'=>true),
 array('igv, total, descuento_total', 'numerical'),
 array('id_proveedor, id_tipo_pago', 'length', 'max'=>10),
 array('nro_documento', 'length', 'max'=>30),
 array('user', 'length', 'max'=>50),
 array('obs,fecha_registro,fecha_eliminacion', 'safe'),
 // The following rule is used by search().
 // Please remove those attributes that should not be searched.
 array('id_compra, id_proveedor, nro_documento, fecha_compra, fecha_registro, estado, user, id_tipo_documento, igv, total, obs, id_tipo_pago, descuento_total, date_first, date_last,date_first2, date_last2', 'safe', 'on'=>'search'),
 );
 }

/**
 * @return array relational rules.
 */
 public function relations()
 {
 // NOTE: you may need to adjust the relation name and the related
 // class name for the relations automatically generated below.
 return array(
 'idTipoDocumento' => array(self::BELONGS_TO, 'TiposDocumentos', 'id_tipo_documento'),
 'idTipoPago' => array(self::BELONGS_TO, 'FormasPago', 'id_tipo_pago'),
 'idProveedor' => array(self::BELONGS_TO, 'Proveedores', 'id_proveedor'),
 );
 }

/**
 * @return array customized attribute labels (name=>label)
 */
 public function attributeLabels()
 {
 return array(
 'id_compra' => 'Compra',
 'id_proveedor' => 'Proveedor',
 'nro_documento' => 'N. Ref',
 'fecha_compra' => 'Fecha',
 'fecha_registro' => 'Fecha Requerida',
 'user' => 'Creado por',
 'id_tipo_documento' => 'Documento',
 //'sub_total' => 'SubTotal',
 'igv' => 'IVA',
 'total' => 'Total',
 'descuento_total' => 'Descuento',
 'obs' => 'Obs',
 'id_tipo_pago' => 'Pago',
 );
 }

/*public static function getEstado($valor){
 return $valor==1?"Aprobado":"Cancelado";
 }

 public static function getListEstados()
 {
 return array('1'=>'Aprobado','0'=>'Cancelado');
 }*/

 /**
 * Retrieves a list of models based on the current search/filter conditions.
 * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
 */
 public function search()
 {
 // Warning: Please modify the following code to remove attributes that
 // should not be searched.

$criteria=new CDbCriteria;
 $session=new CHttpSession;

 $criteria->compare('id_compra',$this->id_compra,true);
 $criteria->compare('id_proveedor',$this->id_proveedor,true);
 $criteria->compare('nro_documento',$this->nro_documento,true);
 $criteria->compare('fecha_compra',$this->fecha_compra,true);
 $criteria->compare('fecha_registro',$this->fecha_registro,true);
 //$criteria->compare('estado',$this->estado,true);
 $criteria->compare('user',$this->user,true);
 $criteria->compare('id_tipo_documento',$this->id_tipo_documento);
 //$criteria->compare('sub_total',$this->sub_total);
 $criteria->compare('igv',$this->igv);
 $criteria->compare('total',$this->total);
 $criteria->compare('obs',$this->obs,true);
 $criteria->compare('id_tipo_pago',$this->id_tipo_pago,true);
 $criteria->compare('descuento_total',$this->descuento_total);

 if((isset($this->date_first) && trim($this->date_first) != "") && (isset($this->date_last) && trim($this->date_last) != ""))
 $criteria->addBetweenCondition('fecha_compra', ''.$this->date_first.'', ''.$this->date_last.'');

 if((isset($this->date_first2) && trim($this->date_first2) != "") && (isset($this->date_last2) && trim($this->date_last2) != ""))
 $criteria->addBetweenCondition('fecha_registro', ''.$this->date_first2.'', ''.$this->date_last2.'');

 $session->open();
 $session['cab-compra_records']=$criteria;

 return new CActiveDataProvider($this, array(
 'pagination'=>array(
 'pageSize'=>5
 ),
 'criteria'=>$criteria,
 ));
 }

public function setListProductos($productos){
 $this->listProductos = $productos;
 $mdlProductos = array();
 foreach($this->listProductos as $producto){
 $tmpProducto = new Detallecompra();
 $tmpProducto->attributes = $producto;
 $mdlProductos[] = $tmpProducto;
 }
 $this->listProductos = $mdlProductos;
 }
}

Modelo DetalleCompra.php (ubicado en la carpeta models):


<?php

/**
 * This is the model class for table "det_compra2".
 *
 * The followings are the available columns in table 'det_compra2':
 * @property string $id_detalle
 * @property string $id_compra
 * @property string $id_producto
 * @property double $precio_unitario
 * @property integer $cantidad_producto
 * @property double $descuento_producto
 * @property string $subtotal_iva
 * @property double $subtotal_producto
 */
class DetalleCompra extends CActiveRecord
{
 /**
 * Returns the static model of the specified AR class.
 * @param string $className active record class name.
 * @return DetCompra2 the static model class
 */
 public static function model($className=__CLASS__)
 {
 return parent::model($className);
 }

/**
 * @return string the associated database table name
 */
 public function tableName()
 {
 return 'det_compra';
 }

/**
 * @return array validation rules for model attributes.
 */
 public function rules()
 {
 // NOTE: you should only define rules for those attributes that
 // will receive user inputs.
 return array(
 array('id_producto, precio_unitario, cantidad_producto, subtotal_producto', 'required'),
 array('cantidad_producto', 'numerical', 'integerOnly'=>true),
 array('precio_unitario, descuento_producto, subtotal_producto', 'numerical'),
 array('id_compra, id_producto', 'length', 'max'=>10),
 array('subtotal_iva', 'length', 'max'=>9),
 // The following rule is used by search().
 // Please remove those attributes that should not be searched.
 array('id_detalle, id_compra, id_producto, precio_unitario, cantidad_producto, descuento_producto, subtotal_iva, subtotal_producto', 'safe', 'on'=>'search'),
 );
 }

/**
 * @return array relational rules.
 */
 public function relations()
 {
 // NOTE: you may need to adjust the relation name and the related
 // class name for the relations automatically generated below.
 return array(
 'compra' => array(self::BELONGS_TO, 'CabCompra', 'id_compra'),
 'producto' => array(self::BELONGS_TO, 'Productos', 'id_producto'),
 );
 }

/**
 * @return array customized attribute labels (name=>label)
 */
 public function attributeLabels()
 {
 return array(
 'id_detalle' => 'Id',
 'id_compra' => 'Compra',
 'id_producto' => 'DESCRIPCION',
 'precio_unitario' => 'PRECIO UNITARIO',
 'cantidad_producto' => 'CANTIDAD',
 'descuento_producto' => 'DESC %',
 'subtotal_iva' => 'IVA %',
 'subtotal_producto' => 'TOTAL',
 );
 }

/**
 * Retrieves a list of models based on the current search/filter conditions.
 * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
 */
 public function search()
 {
 // Warning: Please modify the following code to remove attributes that
 // should not be searched.

$criteria=new CDbCriteria;
 $criteria->with=array('compra','producto');
 if (isset($_GET['DetalleCompra']))
 {
 $model=new DetalleCompra('search');
 $model->attributes = $_GET['DetalleCompra'];
 $criteria->condition='t.id_compra='.$model->id_compra;
 }
 else
 {
 $criteria->condition='t.id_compra=0';
 }

 $criteria->compare('id_detalle',$this->id_detalle,true);
 $criteria->compare('compra.id_compra',$this->id_compra);
 $criteria->compare('id_producto',$this->id_producto);
 $criteria->compare('precio_unitario',$this->precio_unitario);
 $criteria->compare('cantidad_producto',$this->cantidad_producto);
 $criteria->compare('descuento_producto',$this->descuento_producto);
 $criteria->compare('subtotal_iva',$this->subtotal_iva);
 $criteria->compare('subtotal_producto',$this->subtotal_producto);

 return new CActiveDataProvider($this, array(
 'criteria'=>$criteria,
 'pagination'=>array(
 'pageSize'=>5
 ),
 ));
 }
}

Acerca del autor: Rodrigo Paszniuk

Ingeniero Informático, amante de la tecnología, la música, el ciclismo y aprender cosas nuevas.

Posts Relacionados

  • Phalcon – Framework PHP – Extensión de C
  • Reportes gráficos en Yii
  • Backup en Yii
  • Manual intermedio de Yii framework (PHP)



SEGUÍNOS EN FACEBOOK


GITHUB