static void ValidateAndThrowHttpError(this ComprobanteIngresoItem request,
                                                       ComprobanteIngresoItem oldData,
                                                       ComprobanteIngreso comprobante,
                                                       Ingreso ingreso,string ruleSet)
        {
            IngresoCI ece= new IngresoCI(){
                Ingreso=ingreso,
                Ce= comprobante,
                Cei= request,
                OldCei= oldData,
            };
            IngresoCIValidator av = new IngresoCIValidator();

            av.ValidateAndThrowHttpError(ece,ruleSet );
        }
        public static Response<ComprobanteIngreso> Patch(this ComprobanteIngreso request,
                                             Factory factory,
                                             IAuthSession authSession,
                                             string action)
        {
            int factor;
            string operacion;
            string rule;
            Action<DALProxy> toDo=null;

            if(action=="asentar")
            {
                rule=Definiciones.CheckRequestBeforeAsentar;
                operacion= Operaciones.Asentar;
                factor=1;
                toDo= request.Asentar;
            }
            else if(action=="reversar")
            {
                rule=Definiciones.CheckRequestBeforeReversar;
                operacion= Operaciones.Reversar;
                factor=-1;
                toDo=request.Reversar;
            }
            else if(action=="anular")
            {
                 rule= Definiciones.CheckRequestBeforeAnular;
                 operacion= Operaciones.Anular;
                 factor=0;
            }
            else
                throw new HttpError(string.Format("Operacion:'{0}' NO implementada para ComprobanteIngreso",
                                                      action ));            
            
            var idUsuario = int.Parse(authSession.UserAuthId);

            factory.Execute(proxy=>{
                using(proxy.AcquireLock(request.GetLockKey(), Definiciones.LockSeconds))
                {
                    ComprobanteIngreso oldData= proxy.FirstOrDefaultById<ComprobanteIngreso>(request.Id);
					oldData.ValidateAndThrowHttpError(rule);
                    oldData.AssertExists(request.Id);
                    CheckBeforePatch(oldData, request, proxy, idUsuario, operacion);

                    if(factor==0)
                    {
                        proxy.BeginDbTransaction();
                        request.Anular(proxy,"Anulado por Usuario");
                        proxy.CommitDbTransaction();
                        return;
                    }

                    List<ComprobanteIngresoItem> items = proxy.Get<ComprobanteIngresoItem>(q=> q.IdComprobanteIngreso==request.Id);

                    proxy.BeginDbTransaction();
                    #region ActualizarCuentaPorPagar
                    foreach(ComprobanteIngresoItem cei in items)
                    {
                        using (proxy.AcquireLock(cei.IdIngreso.GetLockKey<Ingreso>(), Definiciones.LockSeconds))
                        {
                            var ingreso = proxy.FirstOrDefaultById<Ingreso>( cei.IdIngreso);

							if(operacion=="asentar")
							{
                            	var ece= new IngresoCI(){Ingreso=ingreso, Cei= cei};
                            	var ecv= new IngresoCIValidator();
                            	ecv.ValidateAndThrowHttpError(ece, Operaciones.ActualizarValorIngresoAlAsentarCI);
							}

                            ingreso.Saldo= ingreso.Saldo-( cei.Abono*factor);
                            ingreso.ActualizarValorSaldo(proxy);

                            var  prs= DAL.GetPresupuestoActivo(proxy,request.IdSucursal,Definiciones.IdCentroGeneral);
                            prs.AssertExistsActivo(request.IdSucursal, Definiciones.IdCentroGeneral);

                            CodigoDocumento cd = proxy.GetCodigoDocumento(ingreso.CodigoDocumento);
                            cd.AssertExists(ingreso.CodigoDocumento);
                            cd.AssertEstaActivo();

                            //urn:PresupuestoItem:IdPresupuesto:{0}:Codigo:{1}"
                            using(proxy.AcquireLock(prs.GetLockKey(cd.CodigoPresupuesto), Definiciones.LockSeconds))
                            {
                                var pi= prs.GetPresupuestoItem(proxy,cd.CodigoPresupuesto);
                                pi.AssertExists(prs.Id,cd.CodigoPresupuesto );
                                pi.UpdatePresupuesto(proxy,request.IdSucursal,Definiciones.IdCentroGeneral,
                                                     request.Periodo,
                                                     (cei.Abono>0?(short)2:(short)1),
                                                     Math.Abs(cei.Abono)*factor,request.IdTercero);
                            }

                            var retList = proxy.Get<ComprobanteIngresoRetencion>(q=>q.IdComprobanteIngresoItem==cei.Id);
                            foreach(ComprobanteIngresoRetencion ret in retList)
                            {
                                using(proxy.AcquireLock(ret.IdPresupuestoItem.GetLockKey<PresupuestoItem>(), Definiciones.LockSeconds))
                                {
                                    var pi= DAL.GetPresupuestoItem(proxy,ret.IdPresupuestoItem);
                                    pi.AssertExists(ret.IdPresupuestoItem);
                                    pi.UpdatePresupuesto(proxy, request.IdSucursal,
                                                         Definiciones.IdCentroGeneral,request.Periodo,
                                                         (ret.Valor>0?(short)1:(short)2), 
                                                         Math.Abs(ret.Valor)*factor, null);
                                }
                            }
                        }

                    }
                    //Actualizar Valor en Comprobante Ingreso  NO
                    // Actualizar el presupuesto_item  de la cuenta giradora....

                    using(proxy.AcquireLock(request.IdCuentaReceptora.GetLockKey<PresupuestoItem>(), Definiciones.LockSeconds))
                    {
                        var pi= DAL.GetPresupuestoItem(proxy,request.IdCuentaReceptora);
                        pi.AssertExists(request.IdCuentaReceptora);

                        pi.UpdatePresupuesto(proxy, request.IdSucursal,
                                             Definiciones.IdCentroGeneral,request.Periodo,
                                             (request.Valor>0?(short)1:(short)2),
                                             request.Valor*factor, null);
                    }

                    //}
                    #endregion ActualizarCuentaPorPagar

                    toDo(proxy);
                    proxy.CommitDbTransaction();

                }
            });


                    
            List<ComprobanteIngreso> data = new List<ComprobanteIngreso>();
            data.Add(request);
            
            return new Response<ComprobanteIngreso>(){
                Data=data
            };  
            
        }